eip-cloud-services 1.1.4 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/s3.js +63 -41
package/package.json
CHANGED
package/src/s3.js
CHANGED
|
@@ -38,8 +38,9 @@
|
|
|
38
38
|
* and ensures the best CWVs performance.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
const { S3Client, HeadObjectCommand, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, CopyObjectCommand,
|
|
41
|
+
const { S3Client, HeadObjectCommand, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, CopyObjectCommand, ListObjectsV2Command } = require ( '@aws-sdk/client-s3' );
|
|
42
42
|
const fs = require ( 'fs' );
|
|
43
|
+
const path = require ( 'path' );
|
|
43
44
|
let config = {};
|
|
44
45
|
const configDirPath = `${ process.cwd ()}/config`;
|
|
45
46
|
if ( fs.existsSync ( configDirPath ) && fs.statSync ( configDirPath ).isDirectory () ) {
|
|
@@ -82,14 +83,16 @@ exports.exists = async ( key, bucket = config?.s3?.Bucket ) => {
|
|
|
82
83
|
};
|
|
83
84
|
|
|
84
85
|
/**
|
|
85
|
-
* Get an object from S3.
|
|
86
|
+
* Get an object from S3 and optionally download it to a file.
|
|
86
87
|
*
|
|
87
88
|
* @param {string} key - The object key.
|
|
88
89
|
* @param {string} [bucket=config?.s3?.Bucket] - The bucket name. Defaults to the configured bucket.
|
|
89
|
-
* @
|
|
90
|
-
* @
|
|
90
|
+
* @param {Object} [options] - Optional parameters, including targetFolder for file download.
|
|
91
|
+
* @param {string} [options.targetFolder] - If provided the requested object will be downloaded to this folder instead of being returned. The response will be the file path.
|
|
92
|
+
* @returns {Promise} A promise that resolves to the retrieved object or the path to the downloaded file.
|
|
93
|
+
* @description Retrieves an object from S3 based on the provided key and optionally downloads it to a specified folder.
|
|
91
94
|
*/
|
|
92
|
-
exports.get = async ( key, bucket = config?.s3?.Bucket ) => {
|
|
95
|
+
exports.get = async ( key, bucket = config?.s3?.Bucket, options = {} ) => {
|
|
93
96
|
try {
|
|
94
97
|
const command = new GetObjectCommand ( {
|
|
95
98
|
Bucket: bucket,
|
|
@@ -98,50 +101,69 @@ exports.get = async ( key, bucket = config?.s3?.Bucket ) => {
|
|
|
98
101
|
|
|
99
102
|
if ( config?.s3?.logs === 'verbose' )
|
|
100
103
|
log ( `S3 [GET]: Getting ${bucket}/${key}.` );
|
|
101
|
-
|
|
104
|
+
|
|
102
105
|
const response = await S3.send ( command );
|
|
103
|
-
let data = await streamToBuffer ( response.Body );
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
// If options.targetFolder is specified, download the file
|
|
108
|
+
if ( options.targetFolder ) {
|
|
109
|
+
const filePath = path.join ( options.targetFolder, key.replace ( /\//g, '_' ) );
|
|
110
|
+
const fileStream = fs.createWriteStream ( filePath );
|
|
111
|
+
response.Body.pipe ( fileStream );
|
|
112
|
+
await new Promise ( ( resolve, reject ) => {
|
|
113
|
+
fileStream.on ( 'finish', resolve );
|
|
114
|
+
fileStream.on ( 'error', reject );
|
|
115
|
+
} );
|
|
106
116
|
|
|
107
|
-
if ( config?.s3?.logs === 'verbose' )
|
|
108
|
-
log ( `S3 [GET]: ${key}
|
|
117
|
+
if ( config?.s3?.logs === 'outputs' || config?.s3?.logs === 'verbose' )
|
|
118
|
+
log ( `S3 [GET]: Downloaded ${key} to ${filePath}.` );
|
|
109
119
|
|
|
110
|
-
|
|
111
|
-
}
|
|
120
|
+
return filePath;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
|
|
124
|
+
let data = await streamToBuffer ( response.Body );
|
|
112
125
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
126
|
+
if ( response.ContentEncoding && response.ContentEncoding === 'gzip' ) {
|
|
127
|
+
|
|
128
|
+
if ( config?.s3?.logs === 'verbose' )
|
|
129
|
+
log ( `S3 [GET]: ${key} on ${bucket} was unzipped (was gzipped).` );
|
|
130
|
+
|
|
131
|
+
data = zlib.unzipSync ( data );
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if ( response.ContentType !== 'application/json' && !response.Metadata[ 'tmg-json' ] ) {
|
|
135
|
+
if ( config?.s3?.logs === 'output' )
|
|
136
|
+
log ( `S3 [GET]: Returned ${response.ContentType} from ${bucket}/${key}.` );
|
|
137
|
+
|
|
138
|
+
return data.toString ( 'utf8' );
|
|
139
|
+
}
|
|
116
140
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Buffer.from (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if ( config?.s3?.logs === 'verbose' )
|
|
138
|
-
log ( `S3 [GET]: ${key} on ${bucket} - JSON content was decrypted.` );
|
|
139
|
-
}
|
|
141
|
+
if ( ( response.ContentType === 'application/json' || response.Metadata[ 'tmg-json' ] ) && response.Metadata[ 'tmg-crypt' ] && response.Metadata[ 'tmg-crypt-vec' ] ) {
|
|
142
|
+
const key = await crypto.subtle.importKey (
|
|
143
|
+
'raw',
|
|
144
|
+
Buffer.from ( response.Metadata[ 'tmg-crypt' ], 'base64' ),
|
|
145
|
+
{ name: 'AES-CBC', length: 256 },
|
|
146
|
+
false,
|
|
147
|
+
[ 'decrypt' ]
|
|
148
|
+
);
|
|
149
|
+
const iv = Buffer.from ( response.Metadata[ 'tmg-crypt-vec' ], 'base64' );
|
|
150
|
+
const decryptedArrayBuffer = await crypto.subtle.decrypt (
|
|
151
|
+
{ name: 'AES-CBC', iv },
|
|
152
|
+
key,
|
|
153
|
+
Buffer.from ( data.toString (), 'base64' )
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
data = Buffer.from ( decryptedArrayBuffer ).toString ( 'utf8' );
|
|
157
|
+
|
|
158
|
+
if ( config?.s3?.logs === 'verbose' )
|
|
159
|
+
log ( `S3 [GET]: ${key} on ${bucket} - JSON content was decrypted.` );
|
|
160
|
+
}
|
|
140
161
|
|
|
141
|
-
|
|
142
|
-
|
|
162
|
+
if ( config?.s3?.logs === 'output' )
|
|
163
|
+
log ( `S3 [GET]: ${bucket}/${key} - JSON content was returned.` );
|
|
143
164
|
|
|
144
|
-
|
|
165
|
+
return JSON.parse ( data.toString ( 'utf8' ) );
|
|
166
|
+
}
|
|
145
167
|
}
|
|
146
168
|
catch ( error ) {
|
|
147
169
|
if ( error.Code === 'NoSuchKey' ) {
|