@@ -4,16 +4,26 @@ const {
44 PutObjectCommand,
55 ListObjectsCommand,
66 ListObjectsV2Command,
7+ S3Client,
78} = require ( '@aws-sdk/client-s3' ) ;
8- const { parseString } = require ( 'xml2js' ) ;
9+ const { streamCollector } = require ( '@smithy/node-http-handler' ) ;
10+ const {
11+ IAMClient,
12+ CreatePolicyCommand,
13+ CreateUserCommand,
14+ AttachUserPolicyCommand,
15+ CreateAccessKeyCommand,
16+ DetachUserPolicyCommand,
17+ DeletePolicyCommand,
18+ DeleteUserCommand,
19+ } = require ( '@aws-sdk/client-iam' ) ;
20+ const { parseStringPromise } = require ( 'xml2js' ) ;
921
1022const withV4 = require ( '../support/withV4' ) ;
1123const BucketUtility = require ( '../../lib/utility/bucket-util' ) ;
1224const bucketSchema = require ( '../../schema/bucket' ) ;
1325const bucketSchemaV2 = require ( '../../schema/bucketV2' ) ;
1426const { generateToken, decryptToken } = require ( '../../../../../lib/api/apiUtils/object/continueToken' ) ;
15- const AWS = require ( 'aws-sdk' ) ;
16- const { IAM } = AWS ;
1727const getConfig = require ( '../support/config' ) ;
1828const { config } = require ( '../../../../../lib/Config' ) ;
1929
@@ -552,106 +562,134 @@ describe('GET Bucket - AWS.S3.listObjects', () => {
552562
553563 const iamConfig = getConfig ( 'default' , { region : 'us-east-1' } ) ;
554564 iamConfig . endpoint = `http://${ vaultHost } :8600` ;
555- const iamClient = new IAM ( iamConfig ) ;
565+ const iamClient = new IAMClient ( iamConfig ) ;
556566
557567 before ( async ( ) => {
558- const policyRes = await iamClient
559- . createPolicy ( {
560- PolicyName : 'bp-bypass-policy' ,
561- PolicyDocument : JSON . stringify ( {
562- Version : '2012-10-17' ,
563- Statement : [ {
564- Sid : 'AllowS3ListBucket' ,
565- Effect : 'Allow' ,
566- Action : [
567- 's3:ListBucket' ,
568- ] ,
569- Resource : [ '*' ] ,
570- } ] ,
571- } ) ,
572- } )
573- . promise ( ) ;
568+ const policyRes = await iamClient . send ( new CreatePolicyCommand ( {
569+ PolicyName : 'bp-bypass-policy' ,
570+ PolicyDocument : JSON . stringify ( {
571+ Version : '2012-10-17' ,
572+ Statement : [ {
573+ Sid : 'AllowS3ListBucket' ,
574+ Effect : 'Allow' ,
575+ Action : [
576+ 's3:ListBucket' ,
577+ ] ,
578+ Resource : [ '*' ] ,
579+ } ] ,
580+ } ) ,
581+ } ) ) ;
574582 policyWithoutPermission = policyRes . Policy ;
575- const userRes = await iamClient . createUser ( { UserName : 'user-without-permission' } ) . promise ( ) ;
583+ const userRes = await iamClient . send ( new CreateUserCommand ( { UserName : 'user-without-permission' } ) ) ;
576584 userWithoutPermission = userRes . User ;
577- await iamClient
578- . attachUserPolicy ( {
579- UserName : userWithoutPermission . UserName ,
580- PolicyArn : policyWithoutPermission . Arn ,
581- } )
582- . promise ( ) ;
583-
584- const accessKeyRes = await iamClient . createAccessKey ( {
585+ await iamClient . send ( new AttachUserPolicyCommand ( {
585586 UserName : userWithoutPermission . UserName ,
586- } ) . promise ( ) ;
587+ PolicyArn : policyWithoutPermission . Arn ,
588+ } ) ) ;
589+
590+ const accessKeyRes = await iamClient . send ( new CreateAccessKeyCommand ( {
591+ UserName : userWithoutPermission . UserName ,
592+ } ) ) ;
587593 const accessKey = accessKeyRes . AccessKey ;
588594 const s3Config = getConfig ( 'default' , {
589- credentials : new AWS . Credentials ( accessKey . AccessKeyId , accessKey . SecretAccessKey ) ,
595+ credentials : {
596+ accessKeyId : accessKey . AccessKeyId ,
597+ secretAccessKey : accessKey . SecretAccessKey ,
598+ } ,
590599 } ) ;
591- s3ClientWithoutPermission = new AWS . S3 ( s3Config ) ;
600+ s3ClientWithoutPermission = new S3Client ( s3Config ) ;
592601 } ) ;
593602
594603 after ( async ( ) => {
595- await iamClient
596- . detachUserPolicy ( {
597- UserName : userWithoutPermission . UserName ,
598- PolicyArn : policyWithoutPermission . Arn ,
599- } )
600- . promise ( ) ;
601- await iamClient . deletePolicy ( { PolicyArn : policyWithoutPermission . Arn } ) . promise ( ) ;
602- await iamClient . deleteUser ( { UserName : userWithoutPermission . UserName } ) . promise ( ) ;
604+ await iamClient . send ( new DetachUserPolicyCommand ( {
605+ UserName : userWithoutPermission . UserName ,
606+ PolicyArn : policyWithoutPermission . Arn ,
607+ } ) ) ;
608+ await iamClient . send ( new DeletePolicyCommand ( { PolicyArn : policyWithoutPermission . Arn } ) ) ;
609+ await iamClient . send ( new DeleteUserCommand ( { UserName : userWithoutPermission . UserName } ) ) ;
603610 } ) ;
604611
605- // eslint-disable-next-line max-len
606- const listObjectsV2WithOptionalAttributes = async ( s3 , bucket , headerValue ) => await new Promise ( ( resolve , reject ) => {
612+ const listObjectsV2WithOptionalAttributes = async ( s3 , bucket , headerValue ) => {
613+ const localS3 = s3 ;
607614 let rawXml = '' ;
608- const req = s3 . listObjectsV2 ( { Bucket : bucket } ) ;
609615
610- req . on ( 'build' , ( ) => {
611- req . httpRequest . headers [ 'x-amz-optional-object-attributes' ] = headerValue ;
612- } ) ;
613- req . on ( 'httpData' , chunk => { rawXml += chunk ; } ) ;
614- req . on ( 'error' , err => reject ( err ) ) ;
615- req . on ( 'success' , response => {
616- parseString ( rawXml , ( err , parsedXml ) => {
617- if ( err ) {
618- return reject ( err ) ;
619- }
616+ const addHeaderMiddleware = next => async args => {
617+ const localArgs = args ;
618+ localArgs . request . headers [ 'x-amz-optional-object-attributes' ] = headerValue ;
619+ return next ( localArgs ) ;
620+ } ;
620621
621- const contents = response . data . Contents ;
622- const parsedContents = parsedXml . ListBucketResult . Contents ;
622+ const originalHandler = s3 . config . requestHandler ;
623+ const wrappedHandler = {
624+ async handle ( request , options ) {
625+ const { response } = await originalHandler . handle ( request , options ) ;
623626
624- if ( ! contents || ! parsedContents ) {
625- return resolve ( response . data ) ;
626- }
627+ if ( response && response . body ) {
628+ const collected = await streamCollector ( response . body ) ;
629+ const buffer = Buffer . from ( collected ) ;
630+ rawXml = buffer . toString ( 'utf-8' ) ;
627631
628- if ( parsedContents [ 0 ] ?. [ 'x-amz-meta-department' ] ) {
629- contents [ 0 ] [ 'x-amz-meta-department' ] = parsedContents [ 0 ] [ 'x-amz-meta-department' ] [ 0 ] ;
632+ const { Readable } = require ( 'stream' ) ;
633+ response . body = Readable . from ( [ buffer ] ) ;
630634 }
631635
632- if ( parsedContents [ 0 ] ?. [ 'x-amz-meta-hr' ] ) {
633- contents [ 0 ] [ 'x-amz-meta-hr' ] = parsedContents [ 0 ] [ 'x-amz-meta-hr' ] [ 0 ] ;
636+ return { response } ;
637+ } ,
638+ destroy ( ) {
639+ if ( originalHandler . destroy ) {
640+ originalHandler . destroy ( ) ;
634641 }
642+ }
643+ } ;
635644
636- return resolve ( response . data ) ;
637- } ) ;
645+ localS3 . config . requestHandler = wrappedHandler ;
646+ localS3 . middlewareStack . add ( addHeaderMiddleware , {
647+ step : 'build' ,
648+ name : 'addOptionalAttributesHeader' ,
638649 } ) ;
639650
640- req . send ( ) ;
641- } ) ;
651+ try {
652+ const result = await s3 . send ( new ListObjectsV2Command ( { Bucket : bucket } ) ) ;
653+
654+ if ( ! rawXml ) {
655+ return result ;
656+ }
657+
658+ const parsedXml = await parseStringPromise ( rawXml ) ;
659+ const contents = result . Contents ;
660+ const parsedContents = parsedXml ?. ListBucketResult ?. Contents ;
661+
662+ if ( ! contents || ! parsedContents ) {
663+ return result ;
664+ }
665+
666+ if ( parsedContents [ 0 ] ?. [ 'x-amz-meta-department' ] ) {
667+ contents [ 0 ] [ 'x-amz-meta-department' ] = parsedContents [ 0 ] [ 'x-amz-meta-department' ] [ 0 ] ;
668+ }
669+
670+ if ( parsedContents [ 0 ] ?. [ 'x-amz-meta-hr' ] ) {
671+ contents [ 0 ] [ 'x-amz-meta-hr' ] = parsedContents [ 0 ] [ 'x-amz-meta-hr' ] [ 0 ] ;
672+ }
673+
674+ return result ;
675+ } finally {
676+ localS3 . config . requestHandler = originalHandler ;
677+ localS3 . middlewareStack . remove ( 'addOptionalAttributesHeader' ) ;
678+ }
679+ } ;
642680
643681 it ( 'should return an XML if the header is set' , async ( ) => {
644682 const s3 = bucketUtil . s3 ;
645683 const Bucket = bucketName ;
646684
647- await s3 . putObject ( {
685+ await s3 . send ( new PutObjectCommand ( {
648686 Bucket,
649687 Key : 'super-power-object' ,
650688 Metadata : {
651- Department : 'sales' ,
652- HR : 'true' ,
689+ department : 'sales' ,
690+ hr : 'true' ,
653691 } ,
654- } ) . promise ( ) ;
692+ } ) ) ;
655693 const result = await listObjectsV2WithOptionalAttributes (
656694 s3 ,
657695 Bucket ,
@@ -668,14 +706,14 @@ describe('GET Bucket - AWS.S3.listObjects', () => {
668706 const s3 = bucketUtil . s3 ;
669707 const Bucket = bucketName ;
670708
671- await s3 . putObject ( {
709+ await s3 . send ( new PutObjectCommand ( {
672710 Bucket,
673711 Key : 'super-power-object' ,
674712 Metadata : {
675- Department : 'sales' ,
676- HR : 'true' ,
713+ department : 'sales' ,
714+ hr : 'true' ,
677715 } ,
678- } ) . promise ( ) ;
716+ } ) ) ;
679717
680718 try {
681719 await listObjectsV2WithOptionalAttributes (
@@ -685,23 +723,26 @@ describe('GET Bucket - AWS.S3.listObjects', () => {
685723 ) ;
686724 throw new Error ( 'Request should have been rejected' ) ;
687725 } catch ( err ) {
688- assert . strictEqual ( err . statusCode , 403 ) ;
689- assert . strictEqual ( err . code , 'AccessDenied' ) ;
726+ if ( err . message === 'Request should have been rejected' ) {
727+ throw err ;
728+ }
729+ assert . strictEqual ( err . $metadata . httpStatusCode , 403 ) ;
730+ assert . strictEqual ( err . name , 'AccessDenied' ) ;
690731 }
691732 } ) ;
692733
693734 it ( 'should always (ignore permission) return an XML when the header is RestoreStatus' , async ( ) => {
694735 const s3 = bucketUtil . s3 ;
695736 const Bucket = bucketName ;
696737
697- await s3 . putObject ( {
738+ await s3 . send ( new PutObjectCommand ( {
698739 Bucket,
699740 Key : 'super-power-object' ,
700741 Metadata : {
701- Department : 'sales' ,
702- HR : 'true' ,
742+ department : 'sales' ,
743+ hr : 'true' ,
703744 } ,
704- } ) . promise ( ) ;
745+ } ) ) ;
705746 const result = await listObjectsV2WithOptionalAttributes (
706747 s3ClientWithoutPermission ,
707748 Bucket ,
0 commit comments