117
117
# Unicode letter categories as defined on
118
118
# http://www.unicode.org/reports/tr44/#GC_Values_Table
119
119
# TODO: should we go all in and allow even these very exotic modifiers?
120
- #_ACCENT_CATS = frozenset(('Lu', 'Ll', 'Lt', 'Lm', 'Lo', ))
120
+ # _ACCENT_CATS = frozenset(('Lu', 'Ll', 'Lt', 'Lm', 'Lo', ))
121
121
_ACCENT_CATS = frozenset (('Lu' , 'Ll' , 'Lt' , ))
122
122
123
123
# Use utf8 byte string representation here ("something" and not u"something")
@@ -879,13 +879,29 @@ def valid_email_address(addr, allow_real_name=True):
879
879
John Doe <john@doe.org>
880
880
"""
881
881
882
+ # TODO: rework this as formataddr does NOT have RFC6532 support on py3
883
+ # and assuming parse+format matches orig also introduces false
884
+ # positives regarding e.g. extra white space in display name.
885
+ # https://github.com/python/cpython/issues/70143
882
886
(real_name , plain_addr ) = name_address_pair = parseaddr (addr )
883
887
if real_name and not allow_real_name :
884
888
raise InputException ("Only plain addresses without name allowed" )
885
889
if not silent_email_validator (plain_addr ):
890
+ # NOTE: email-validator validate_email function ONLY accepts non-ascii
891
+ # chars when passed unicode on py2, so we end up here for valid
892
+ # RFC 6532 addresses when passed as native byte strings.
886
893
raise InputException ("No actual email address included" )
887
- merged = formataddr (name_address_pair )
888
- if merged != addr :
894
+ try :
895
+ merged = formataddr (name_address_pair )
896
+ if merged != addr :
897
+ raise ValueError ("parsed vs raw email mismatch" )
898
+ except (ValueError , UnicodeEncodeError ) as exc :
899
+ # TODO: eliminate this UnicodeEncodeError handling here once reworked
900
+ # NOTE: formataddr does NOT support non-ascii chars on py3 at all and
901
+ # explicitly encodes to ascii so we end up here for valid RFC
902
+ # 6532 addresses. See note and link above for details.
903
+ # print("unicode err in %s" %
904
+ # [addr, real_name, plain_addr, name_address_pair])
889
905
raise InputException ("Invalid email format" )
890
906
891
907
@@ -2281,24 +2297,47 @@ def __str__(self):
2281
2297
return force_utf8 (force_unicode (self .value ))
2282
2298
2283
2299
2284
- def main (_print = print ):
2285
- print = _print # workaround print as reserved word on PY2
2300
+ def main (_exit = sys . exit , _print = print ):
2301
+ print = _print # workaround print as reserved word on PY2
2286
2302
2287
2303
for test_org in ('UCPH' , 'Some University, Some Dept.' , 'Green Shoes Ltd.' ,
2288
- u'Unicode Org' , "Invalid R+D" , "Invalid R/D" ,
2289
- "Invalid R@D" , 'Test HTML Invalid <code/>' ):
2304
+ u'Unicode Org' ):
2305
+ try :
2306
+ print ('Testing valid_organization: %r' % test_org )
2307
+ print ('Filtered organization: %s' % filter_organization (test_org ))
2308
+ valid_organization (test_org )
2309
+ print ('Accepted raw organization!' )
2310
+ except InputException as exc :
2311
+ print ('Rejected raw organization %r: %s' % (test_org , exc ))
2312
+ _exit (1 )
2313
+
2314
+ for test_org in ("Invalid R+D" , "Invalid R/D" , "Invalid R@D" ,
2315
+ 'Test HTML Invalid <code/>' ):
2290
2316
try :
2291
2317
print ('Testing valid_organization: %r' % test_org )
2292
2318
print ('Filtered organization: %s' % filter_organization (test_org ))
2293
2319
valid_organization (test_org )
2294
2320
print ('Accepted raw organization!' )
2295
- except Exception as exc :
2321
+ _exit (1 )
2322
+ except InputException as exc :
2296
2323
print ('Rejected raw organization %r: %s' % (test_org , exc ))
2297
2324
2298
2325
for test_path in ('test.txt' , 'Test Æøå' , 'Test Überh4x0r' ,
2299
2326
'Test valid Jean-Luc Géraud' , 'Test valid Źacãŕ' ,
2300
2327
'Test valid special%&()!$¶â€' , 'Test look-alike-å å' ,
2301
- 'Test north Atlantic Barður Ðýþ' , 'Test exotic لرحيم' ,
2328
+ 'Test north Atlantic Barður Ðýþ' ):
2329
+ try :
2330
+ print ('Testing valid_path: %s' % test_path )
2331
+ print ('Filtered path: %s' % filter_path (test_path ))
2332
+ # print 'DEBUG %s only in %s' % ([test_path],
2333
+ # [VALID_PATH_CHARACTERS])
2334
+ valid_path (test_path )
2335
+ print ('Accepted raw path!' )
2336
+ except InputException as exc :
2337
+ print ('Rejected raw path %r: %s' % (test_path , exc ))
2338
+ _exit (1 )
2339
+
2340
+ for test_path in ('Test exotic لرحيم' ,
2302
2341
'Test Invalid ?' , 'Test Invalid `' ,
2303
2342
'Test invalid <' , 'Test Invalid >' ,
2304
2343
'Test Invalid *' , 'Test Invalid "' ):
@@ -2309,19 +2348,40 @@ def main(_print=print):
2309
2348
# [VALID_PATH_CHARACTERS])
2310
2349
valid_path (test_path )
2311
2350
print ('Accepted raw path!' )
2312
- except Exception as exc :
2351
+ _exit (1 )
2352
+ except InputException as exc :
2313
2353
print ('Rejected raw path %r: %s' % (test_path , exc ))
2314
2354
2315
- for test_addr in ('' , 'invalid' , 'abc@dk' , 'abc@def.org' , 'abc@def.gh.org' ,
2316
- 'aBc@Def.org' , '<invalid@def.org>' ,
2317
- 'Test <abc@def.org>' , 'Test Æøå <æøå@abc.org>' ,
2355
+ # Simple valid addresses to accept
2356
+ for test_addr in ('abc@def.org' , 'abc@def.gh.org' , 'Test <abc@def.org>' ,
2318
2357
'Test <abc.def@ghi.org>' , 'Test <abc+def@ghi.org>' ,
2319
- 'A valid-name <abc@ghi.org>' ,
2358
+ 'A valid-name <abc@ghi.org>' ):
2359
+ try :
2360
+ print ('Testing valid_email_address: %s' % test_addr )
2361
+ valid_email_address (test_addr )
2362
+ print ('Accepted raw address! %s' % [parseaddr (test_addr )])
2363
+ except InputException as exc :
2364
+ print ('Rejected raw address %r: %s' % (test_addr , exc ))
2365
+ _exit (1 )
2366
+
2367
+ # TODO: fix validation and toggle exit back on below
2368
+ # Corner-case valid addresses that we currently don't accept
2369
+ for test_addr in ('Test Æøå <æøå@abc.org>' ,
2370
+ 'aBc@Def.org' , '<valid@def.org>' ,
2320
2371
' false-positive@ghi.org' ,
2321
2372
'False Positive <abc@ghi.org>' ,
2322
- ' Another False Positive <abc@ghi.org>' ,
2323
- 'invalid <abc@ghi,org>' , 'invalid <abc@' ,
2324
- 'invalid abc@def.org' ,
2373
+ ' Another False Positive <abc@ghi.org>' ):
2374
+ try :
2375
+ print ('Testing valid_email_address: %s' % test_addr )
2376
+ valid_email_address (test_addr )
2377
+ print ('Accepted raw address! %s' % [parseaddr (test_addr )])
2378
+ except InputException as exc :
2379
+ print ('Rejected raw address %r: %s' % (test_addr , exc ))
2380
+ # _exit(1)
2381
+
2382
+ # Simple invalid addresses to fail on
2383
+ for test_addr in ('' , 'invalid' , 'abc@dk' , 'invalid <abc@ghi,org>' ,
2384
+ 'invalid <abc@' , 'invalid abc@def.org' ,
2325
2385
'Test <abc@ghi.org>, twice <def@def.org>' ,
2326
2386
'A !#¤%/) positive <abc@ghi.org>' ,
2327
2387
'a@b.c<script>alert("XSS vulnerable");</script>' ,
@@ -2331,7 +2391,8 @@ def main(_print=print):
2331
2391
print ('Testing valid_email_address: %s' % test_addr )
2332
2392
valid_email_address (test_addr )
2333
2393
print ('Accepted raw address! %s' % [parseaddr (test_addr )])
2334
- except Exception as exc :
2394
+ _exit (1 )
2395
+ except InputException as exc :
2335
2396
print ('Rejected raw address %r: %s' % (test_addr , exc ))
2336
2397
2337
2398
# OpenID 2.0 version
@@ -2378,19 +2439,24 @@ def main(_print=print):
2378
2439
print ("Accepted:" )
2379
2440
for (key , val ) in accepted .items ():
2380
2441
print ("\t %s: %s" % (key , val ))
2381
- print ("Rejected:" )
2382
- for (key , val ) in rejected .items ():
2383
- print ("\t %s: %s" % (key , val ))
2442
+ if rejected :
2443
+ print ("Rejected:" )
2444
+ for (key , val ) in rejected .items ():
2445
+ print ("\t %s: %s" % (key , val ))
2446
+ _exit (1 )
2447
+
2384
2448
user_arguments_dict ['openid.sreg.fullname' ] = [
2385
2449
force_unicode ('Jonas Æøå Bardino' )]
2386
2450
(accepted , rejected ) = validated_input (
2387
2451
user_arguments_dict , autocreate_defaults )
2388
2452
print ("Accepted:" )
2389
2453
for (key , val ) in accepted .items ():
2390
2454
print ("\t %s: %s" % (key , val ))
2391
- print ("Rejected:" )
2392
- for (key , val ) in rejected .items ():
2393
- print ("\t %s: %s" % (key , val ))
2455
+ if rejected :
2456
+ print ("Rejected:" )
2457
+ for (key , val ) in rejected .items ():
2458
+ print ("\t %s: %s" % (key , val ))
2459
+ _exit (1 )
2394
2460
2395
2461
# OpenID Connect version
2396
2462
autocreate_defaults = {
@@ -2437,9 +2503,12 @@ def main(_print=print):
2437
2503
print ("Accepted:" )
2438
2504
for (key , val ) in accepted .items ():
2439
2505
print ("\t %s: %s" % (key , val ))
2440
- print ("Rejected:" )
2441
- for (key , val ) in rejected .items ():
2442
- print ("\t %s: %s" % (key , val ))
2506
+ if rejected :
2507
+ print ("Rejected:" )
2508
+ for (key , val ) in rejected .items ():
2509
+ print ("\t %s: %s" % (key , val ))
2510
+ _exit (1 )
2511
+
2443
2512
user_arguments_dict = {'oidc.claim.aud' : ['http://somedomain.org' ],
2444
2513
'oidc.claim.country' : ['DK' ],
2445
2514
'oidc.claim.email' : ['bardino@nbi.ku.dk,bardino@science.ku.dk' ],
@@ -2464,9 +2533,14 @@ def main(_print=print):
2464
2533
print ("Accepted:" )
2465
2534
for (key , val ) in accepted .items ():
2466
2535
print ("\t %s: %s" % (key , val ))
2467
- print ("Rejected:" )
2468
- for (key , val ) in rejected .items ():
2469
- print ("\t %s: %s" % (key , val ))
2536
+ if rejected :
2537
+ print ("Rejected:" )
2538
+ for (key , val ) in rejected .items ():
2539
+ print ("\t %s: %s" % (key , val ))
2540
+ _exit (1 )
2541
+
2542
+ _exit (0 )
2543
+
2470
2544
2471
2545
if __name__ == '__main__' :
2472
2546
main ()
0 commit comments