-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Expand file tree
/
Copy pathpresigned-url-upload.js
More file actions
149 lines (135 loc) · 4.2 KB
/
presigned-url-upload.js
File metadata and controls
149 lines (135 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// snippet-start:[s3.JavaScript.buckets.presignedurlv3]
import https from "node:https";
import { XMLParser } from "fast-xml-parser";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { fromIni } from "@aws-sdk/credential-providers";
import { HttpRequest } from "@smithy/protocol-http";
import {
getSignedUrl,
S3RequestPresigner,
} from "@aws-sdk/s3-request-presigner";
import { parseUrl } from "@smithy/url-parser";
import { formatUrl } from "@aws-sdk/util-format-url";
import { Hash } from "@smithy/hash-node";
const createPresignedUrlWithoutClient = async ({ region, bucket, key }) => {
const url = parseUrl(`https://${bucket}.s3.${region}.amazonaws.com/${key}`);
const presigner = new S3RequestPresigner({
credentials: fromIni(),
region,
sha256: Hash.bind(null, "sha256"),
});
const signedUrlObject = await presigner.presign(
new HttpRequest({ ...url, method: "PUT" }),
);
return formatUrl(signedUrlObject);
};
const createPresignedUrlWithClient = ({ region, bucket, key }) => {
const client = new S3Client({ region });
const command = new PutObjectCommand({ Bucket: bucket, Key: key });
return getSignedUrl(client, command, { expiresIn: 3600 });
};
/**
* Make a PUT request to the provided URL.
*
* @param {string} url
* @param {string} data
*/
const put = (url, data) => {
return new Promise((resolve, reject) => {
const req = https.request(
url,
{ method: "PUT", headers: { "Content-Length": new Blob([data]).size } },
(res) => {
let responseBody = "";
res.on("data", (chunk) => {
responseBody += chunk;
});
res.on("end", () => {
const parser = new XMLParser();
if (res.statusCode >= 200 && res.statusCode <= 299) {
resolve(parser.parse(responseBody, true));
} else {
reject(parser.parse(responseBody, true));
}
});
},
);
req.on("error", (err) => {
reject(err);
});
req.write(data);
req.end();
});
};
/**
* Create two presigned urls for uploading an object to an S3 bucket.
* The first presigned URL is created with credentials from the shared INI file
* in the current environment. The second presigned URL is created using an
* existing S3Client instance that has already been provided with credentials.
* @param {{ bucketName: string, key: string, region: string }}
*/
export const main = async ({ bucketName, key, region }) => {
try {
const noClientUrl = await createPresignedUrlWithoutClient({
bucket: bucketName,
key,
region,
});
const clientUrl = await createPresignedUrlWithClient({
bucket: bucketName,
region,
key,
});
// After you get the presigned URL, you can provide your own file
// data. Refer to put() above.
console.log("Calling PUT using presigned URL without client");
await put(noClientUrl, "Hello World");
console.log("Calling PUT using presigned URL with client");
await put(clientUrl, "Hello World");
console.log("\nDone. Check your S3 console.");
} catch (caught) {
if (caught instanceof Error && caught.name === "CredentialsProviderError") {
console.error(
`There was an error getting your credentials. Are your local credentials configured?\n${caught.name}: ${caught.message}`,
);
} else {
throw caught;
}
}
};
// snippet-end:[s3.JavaScript.buckets.presignedurlv3]
// Call function if run directly
import { parseArgs } from "node:util";
import {
isMain,
validateArgs,
} from "@aws-doc-sdk-examples/lib/utils/util-node.js";
const loadArgs = () => {
const options = {
bucketName: {
type: "string",
required: true,
},
key: {
type: "string",
required: true,
},
region: {
type: "string",
required: true,
},
};
const results = parseArgs({ options });
const { errors } = validateArgs({ options }, results);
return { errors, results };
};
if (isMain(import.meta.url)) {
const { errors, results } = loadArgs();
if (!errors) {
main(results.values);
} else {
console.error(errors.join("\n"));
}
}