2424
2525SMALL_TEST_DATA = [('_ziptest1' , '1q2w3e4r5t' ),
2626 ('ziptest2dir/_ziptest2' , 'qawsedrftg' ),
27- ('/ ziptest2dir/ziptest3dir/_ziptest3' , 'azsxdcfvgb' ),
27+ ('ziptest2dir/ziptest3dir/_ziptest3' , 'azsxdcfvgb' ),
2828 ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3' , '6y7u8i9o0p' )]
2929
3030
@@ -501,10 +501,7 @@ def test_extract(self):
501501 writtenfile = zipfp .extract (fpath )
502502
503503 # make sure it was written to the right place
504- if os .path .isabs (fpath ):
505- correctfile = os .path .join (os .getcwd (), fpath [1 :])
506- else :
507- correctfile = os .path .join (os .getcwd (), fpath )
504+ correctfile = os .path .join (os .getcwd (), fpath )
508505 correctfile = os .path .normpath (correctfile )
509506
510507 self .assertEqual (writtenfile , correctfile )
@@ -526,10 +523,7 @@ def test_extract_all(self):
526523 with zipfile .ZipFile (TESTFN2 , "r" ) as zipfp :
527524 zipfp .extractall ()
528525 for fpath , fdata in SMALL_TEST_DATA :
529- if os .path .isabs (fpath ):
530- outfile = os .path .join (os .getcwd (), fpath [1 :])
531- else :
532- outfile = os .path .join (os .getcwd (), fpath )
526+ outfile = os .path .join (os .getcwd (), fpath )
533527
534528 with open (outfile , "rb" ) as f :
535529 self .assertEqual (fdata .encode (), f .read ())
@@ -539,6 +533,80 @@ def test_extract_all(self):
539533 # remove the test file subdirectories
540534 shutil .rmtree (os .path .join (os .getcwd (), 'ziptest2dir' ))
541535
536+ def check_file (self , filename , content ):
537+ self .assertTrue (os .path .isfile (filename ))
538+ with open (filename , 'rb' ) as f :
539+ self .assertEqual (f .read (), content )
540+
541+ def test_extract_hackers_arcnames (self ):
542+ hacknames = [
543+ ('../foo/bar' , 'foo/bar' ),
544+ ('foo/../bar' , 'foo/bar' ),
545+ ('foo/../../bar' , 'foo/bar' ),
546+ ('foo/bar/..' , 'foo/bar' ),
547+ ('./../foo/bar' , 'foo/bar' ),
548+ ('/foo/bar' , 'foo/bar' ),
549+ ('/foo/../bar' , 'foo/bar' ),
550+ ('/foo/../../bar' , 'foo/bar' ),
551+ ('//foo/bar' , 'foo/bar' ),
552+ ('../../foo../../ba..r' , 'foo../ba..r' ),
553+ ]
554+ if os .path .sep == '\\ ' : # Windows.
555+ hacknames .extend ([
556+ (r'..\foo\bar' , 'foo/bar' ),
557+ (r'..\/foo\/bar' , 'foo/bar' ),
558+ (r'foo/\..\/bar' , 'foo/bar' ),
559+ (r'foo\/../\bar' , 'foo/bar' ),
560+ (r'C:foo/bar' , 'foo/bar' ),
561+ (r'C:/foo/bar' , 'foo/bar' ),
562+ (r'C://foo/bar' , 'foo/bar' ),
563+ (r'C:\foo\bar' , 'foo/bar' ),
564+ (r'//conky/mountpoint/foo/bar' , 'foo/bar' ),
565+ (r'\\conky\mountpoint\foo\bar' , 'foo/bar' ),
566+ (r'///conky/mountpoint/foo/bar' , 'conky/mountpoint/foo/bar' ),
567+ (r'\\\conky\mountpoint\foo\bar' , 'conky/mountpoint/foo/bar' ),
568+ (r'//conky//mountpoint/foo/bar' , 'conky/mountpoint/foo/bar' ),
569+ (r'\\conky\\mountpoint\foo\bar' , 'conky/mountpoint/foo/bar' ),
570+ (r'//?/C:/foo/bar' , 'foo/bar' ),
571+ (r'\\?\C:\foo\bar' , 'foo/bar' ),
572+ (r'C:/../C:/foo/bar' , 'C_/foo/bar' ),
573+ (r'a:b\c<d>e|f"g?h*i' , 'b/c_d_e_f_g_h_i' ),
574+ ])
575+
576+ for arcname , fixedname in hacknames :
577+ content = b'foobar' + arcname .encode ()
578+ with zipfile .ZipFile (TESTFN2 , 'w' , zipfile .ZIP_STORED ) as zipfp :
579+ zipfp .writestr (arcname , content )
580+
581+ targetpath = os .path .join ('target' , 'subdir' , 'subsub' )
582+ correctfile = os .path .join (targetpath , * fixedname .split ('/' ))
583+
584+ with zipfile .ZipFile (TESTFN2 , 'r' ) as zipfp :
585+ writtenfile = zipfp .extract (arcname , targetpath )
586+ self .assertEqual (writtenfile , correctfile )
587+ self .check_file (correctfile , content )
588+ shutil .rmtree ('target' )
589+
590+ with zipfile .ZipFile (TESTFN2 , 'r' ) as zipfp :
591+ zipfp .extractall (targetpath )
592+ self .check_file (correctfile , content )
593+ shutil .rmtree ('target' )
594+
595+ correctfile = os .path .join (os .getcwd (), * fixedname .split ('/' ))
596+
597+ with zipfile .ZipFile (TESTFN2 , 'r' ) as zipfp :
598+ writtenfile = zipfp .extract (arcname )
599+ self .assertEqual (writtenfile , correctfile )
600+ self .check_file (correctfile , content )
601+ shutil .rmtree (fixedname .split ('/' )[0 ])
602+
603+ with zipfile .ZipFile (TESTFN2 , 'r' ) as zipfp :
604+ zipfp .extractall ()
605+ self .check_file (correctfile , content )
606+ shutil .rmtree (fixedname .split ('/' )[0 ])
607+
608+ os .remove (TESTFN2 )
609+
542610 def test_writestr_compression_stored (self ):
543611 zipfp = zipfile .ZipFile (TESTFN2 , "w" )
544612 zipfp .writestr ("a.txt" , "hello world" , compress_type = zipfile .ZIP_STORED )
0 commit comments