@@ -512,5 +512,207 @@ describe('POST object', () => {
512512 } ) ;
513513 } ) ;
514514 } ) ;
515+
516+ it ( 'should handle error when signature is invalid' , done => {
517+ const { url, bucketName } = testContext ;
518+ const fields = calculateFields ( ak , sk , bucketName ) ;
519+ fields . push ( { name : 'X-Amz-Signature' , value : 'invalid-signature' } ) ;
520+ const formData = new FormData ( ) ;
521+
522+ fields . forEach ( field => {
523+ formData . append ( field . name , field . value ) ;
524+ } ) ;
525+
526+ formData . append ( 'file' , fs . createReadStream ( path . join ( __dirname , 'test-file.txt' ) ) ) ;
527+
528+ formData . getLength ( ( err , length ) => {
529+ if ( err ) {
530+ return done ( err ) ;
531+ }
532+
533+ axios . post ( url , formData , {
534+ headers : {
535+ ...formData . getHeaders ( ) ,
536+ 'Content-Length' : length ,
537+ } ,
538+ } )
539+ . then ( ( ) => {
540+ done ( new Error ( 'Expected error but got success response' ) ) ;
541+ } )
542+ . catch ( err => {
543+ assert . equal ( err . response . status , 403 ) ;
544+ done ( ) ;
545+ } ) ;
546+ } ) ;
547+ } ) ;
548+
549+ it ( 'should return an error when signature includes invalid data' , done => {
550+ const { url, bucketName } = testContext ;
551+ let fields = calculateFields ( ak , sk , bucketName ) ;
552+ const laterThanNow = new Date ( new Date ( ) . getTime ( ) + 60000 ) ;
553+ const shortFormattedDate = formatDate ( laterThanNow ) ;
554+
555+ const signingKey = getSignatureKey ( sk , shortFormattedDate , 'ap-east-1' , 's3' ) ;
556+ const signature = crypto . createHmac ( 'sha256' , signingKey ) . update ( fields . find ( field =>
557+ field . name === 'Policy' ) . value ) . digest ( 'hex' ) ;
558+
559+ // Modify the signature to be invalid
560+ fields = fields . map ( field => {
561+ if ( field . name === 'X-Amz-Signature' ) {
562+ return { name : 'X-Amz-Signature' , value : signature } ;
563+ }
564+ return field ;
565+ } ) ;
566+
567+ const formData = new FormData ( ) ;
568+
569+ fields . forEach ( field => {
570+ formData . append ( field . name , field . value ) ;
571+ } ) ;
572+
573+ formData . append ( 'file' , fs . createReadStream ( path . join ( __dirname , 'test-file.txt' ) ) ) ;
574+
575+ formData . getLength ( ( err , length ) => {
576+ if ( err ) {
577+ return done ( err ) ;
578+ }
579+
580+ axios . post ( url , formData , {
581+ headers : {
582+ ...formData . getHeaders ( ) ,
583+ 'Content-Length' : length ,
584+ } ,
585+ } )
586+ . then ( ( ) => {
587+ done ( new Error ( 'Request should not succeed with an invalid signature' ) ) ;
588+ } )
589+ . catch ( err => {
590+ assert . ok ( err . response , 'Error should be returned by axios' ) ;
591+
592+ // Parse the XML error response
593+ xml2js . parseString ( err . response . data , ( parseErr , result ) => {
594+ if ( parseErr ) {
595+ return done ( parseErr ) ;
596+ }
597+
598+ const error = result . Error ;
599+ assert . equal (
600+ error . Code [ 0 ] ,
601+ 'SignatureDoesNotMatch' ,
602+ 'Expected SignatureDoesNotMatch error code'
603+ ) ;
604+ done ( ) ;
605+ } ) ;
606+ } ) ;
607+ } ) ;
608+ } ) ;
609+
610+ it ( 'should return an error for invalid keys' , done => {
611+ const { url, bucketName } = testContext ;
612+ const invalidAccessKeyId = 'INVALIDACCESSKEY' ;
613+ const invalidSecretAccessKey = 'INVALIDSECRETKEY' ;
614+ let fields = calculateFields ( invalidAccessKeyId , invalidSecretAccessKey , bucketName ) ;
615+
616+ // Modify the signature to be invalid
617+ fields = fields . map ( field => {
618+ if ( field . name === 'X-Amz-Signature' ) {
619+ return { name : 'X-Amz-Signature' , value : 'invalid-signature' } ;
620+ }
621+ return field ;
622+ } ) ;
623+
624+ const formData = new FormData ( ) ;
625+
626+ fields . forEach ( field => {
627+ formData . append ( field . name , field . value ) ;
628+ } ) ;
629+
630+ formData . append ( 'file' , fs . createReadStream ( path . join ( __dirname , 'test-file.txt' ) ) ) ;
631+
632+ formData . getLength ( ( err , length ) => {
633+ if ( err ) {
634+ return done ( err ) ;
635+ }
636+
637+ axios . post ( url , formData , {
638+ headers : {
639+ ...formData . getHeaders ( ) ,
640+ 'Content-Length' : length ,
641+ } ,
642+ } )
643+ . then ( ( ) => {
644+ done ( new Error ( 'Request should not succeed with an invalid keys' ) ) ;
645+ } )
646+ . catch ( err => {
647+ assert . ok ( err . response , 'Error should be returned by axios' ) ;
648+
649+ // Parse the XML error response
650+ xml2js . parseString ( err . response . data , ( parseErr , result ) => {
651+ if ( parseErr ) {
652+ return done ( parseErr ) ;
653+ }
654+
655+ const error = result . Error ;
656+ assert . equal ( error . Code [ 0 ] , 'InvalidAccessKeyId' , 'Expected InvalidAccessKeyId error code' ) ;
657+ done ( ) ;
658+ } ) ;
659+ } ) ;
660+ } ) ;
661+ } ) ;
662+
663+ it ( 'should return an error for invalid credential' , done => {
664+ const { url, bucketName } = testContext ;
665+ let fields = calculateFields ( ak , sk , bucketName ) ;
666+ const laterThanNow = new Date ( new Date ( ) . getTime ( ) + 60000 ) ;
667+ const shortFormattedDate = formatDate ( laterThanNow ) ;
668+
669+ const credential = `${ ak } /${ shortFormattedDate } /ap-east-1/s3/aws4_request` ;
670+
671+ // Modify the signature to be invalid
672+ fields = fields . map ( field => {
673+ if ( field . name === 'X-Amz-Credential' ) {
674+ return { name : 'X-Amz-Credential' , value : credential } ;
675+ }
676+ return field ;
677+ } ) ;
678+
679+ const formData = new FormData ( ) ;
680+
681+ fields . forEach ( field => {
682+ formData . append ( field . name , field . value ) ;
683+ } ) ;
684+
685+ formData . append ( 'file' , fs . createReadStream ( path . join ( __dirname , 'test-file.txt' ) ) ) ;
686+
687+ formData . getLength ( ( err , length ) => {
688+ if ( err ) {
689+ return done ( err ) ;
690+ }
691+
692+ axios . post ( url , formData , {
693+ headers : {
694+ ...formData . getHeaders ( ) ,
695+ 'Content-Length' : length ,
696+ } ,
697+ } )
698+ . then ( ( ) => {
699+ done ( new Error ( 'Request should not succeed with an invalid credential' ) ) ;
700+ } )
701+ . catch ( err => {
702+ assert . ok ( err . response , 'Error should be returned by axios' ) ;
703+
704+ // Parse the XML error response
705+ xml2js . parseString ( err . response . data , ( parseErr , result ) => {
706+ if ( parseErr ) {
707+ return done ( parseErr ) ;
708+ }
709+
710+ const error = result . Error ;
711+ assert . equal ( error . Code [ 0 ] , 'InvalidArgument' , 'Expected InvalidArgument error code' ) ;
712+ done ( ) ;
713+ } ) ;
714+ } ) ;
715+ } ) ;
716+ } ) ;
515717} ) ;
516718
0 commit comments