Skip to content

Commit e5728d3

Browse files
committed
updated aws-node-upload-to-s3-and-postprocess example to use signing key with AWS Signature Version 4
(AWS4-HMAC-SHA256)
1 parent b592a93 commit e5728d3

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

aws-node-upload-to-s3-and-postprocess/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ trigger a lambda function.
2323
- Edit `serverless.yml` and choose a unique S3 bucket name.
2424
- Edit `generate-form.js` and fill in your `aws_access_key_id`,
2525
`aws_secret_access_key` and `bucket_name`.
26+
- Run `yarn install` to install crypto-js dependency for `generate-form.js`.
2627
- Generate the HTML form:
2728

2829

2930
```bash
31+
yarn install
3032
node generate-form.js
3133
```
3234

aws-node-upload-to-s3-and-postprocess/frontend/index.template.html

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66

77
<body>
88
<form action="%BUCKET_URL%" method="post" enctype="multipart/form-data">
9-
<input type="hidden" name="Content-Type" value="image/png">
10-
<input type="hidden" name="AWSAccessKeyId" value="%AWS_ACCESS_KEY%">
119
<input type="hidden" name="acl" value="public-read">
10+
<input type="hidden" name="Content-Type" value="image/png">
11+
<input type="hidden" name="x-amz-credential" value="%CREDENTIAL%">
12+
<input type="hidden" name="x-amz-algorithm" value="AWS4-HMAC-SHA256">
13+
<input type="hidden" name="x-amz-date" value="%DATE%">
1214
<input type="hidden" name="success_action_status" value="201">
13-
<input type="hidden" name="policy" value="%POLICY_BASE64%">
14-
<input type="hidden" name="signature" value="%SIGNATURE%">
15+
<input type="hidden" name="Policy" value="%POLICY_BASE64%">
16+
<input type="hidden" name="x-amz-signature" value="%SIGNATURE%">
1517

1618
Destination filename: <input type="text" name="key" value="uploads/image.png">
1719
<br>

aws-node-upload-to-s3-and-postprocess/generate-form.js

+27-8
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,51 @@
11
#!/usr/bin/env node
22

3-
const crypto = require('crypto');
3+
const crypto = require('crypto-js');
4+
const Hex = require('crypto-js/enc-hex');
45
const fs = require('fs');
56

7+
// from: https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-javascript
8+
function getSignatureKey(key, dateStamp, regionName, serviceName) {
9+
const kDate = crypto.HmacSHA256(dateStamp, `AWS4${key}`);
10+
const kRegion = crypto.HmacSHA256(regionName, kDate);
11+
const kService = crypto.HmacSHA256(serviceName, kRegion);
12+
const kSigning = crypto.HmacSHA256('aws4_request', kService);
13+
return kSigning;
14+
}
15+
616
const awsAccessKeyId = '<your access key id>';
717
const awsSecretAccessKey = '<your secret access key>';
818
const bucketName = '<your bucket name>';
19+
const region = '<your region name>';
920

1021
const msPerDay = 24 * 60 * 60 * 1000;
1122
const expiration = new Date(Date.now() + msPerDay).toISOString();
1223
const bucketUrl = `https://${bucketName}.s3.amazonaws.com`;
24+
const date = new Date().toISOString().slice(0, 10).replace(/-/g, '');
25+
const credentials = `${awsAccessKeyId}/${date}/${region}/s3/aws4_request`;
1326

27+
// Sample policy and form: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html
1428
const policy = {
1529
expiration,
1630
conditions: [
17-
['starts-with', '$key', 'uploads/'],
1831
{ bucket: bucketName },
32+
['starts-with', '$key', 'uploads/'],
1933
{ acl: 'public-read' },
2034
['starts-with', '$Content-Type', 'image/png'],
21-
{ success_action_status: '201' },
35+
// ['starts-with', '$success_action_redirect', ''],
36+
['starts-with', '$success_action_status', ''],
37+
38+
{ 'x-amz-credential': credentials },
39+
{ 'x-amz-algorithm': 'AWS4-HMAC-SHA256' },
40+
{ 'x-amz-date': `${date}T000000Z` },
2241
],
2342
};
2443

25-
const policyB64 = Buffer(JSON.stringify(policy), 'utf-8').toString('base64');
44+
const policyB64 = Buffer.from(JSON.stringify(policy), 'utf-8').toString('base64');
2645

27-
const hmac = crypto.createHmac('sha1', awsSecretAccessKey);
28-
hmac.update(new Buffer(policyB64, 'utf-8'));
46+
const sigKey = getSignatureKey(awsSecretAccessKey, date, region, 's3');
2947

30-
const signature = hmac.digest('base64');
48+
const signature = Hex.stringify(crypto.HmacSHA256(policyB64, sigKey));
3149

3250
fs.readFile('frontend/index.template.html', 'utf8', (err, input) => {
3351
if (err) {
@@ -36,8 +54,9 @@ fs.readFile('frontend/index.template.html', 'utf8', (err, input) => {
3654

3755
const data = input
3856
.replace(/%BUCKET_URL%/g, bucketUrl)
39-
.replace(/%AWS_ACCESS_KEY%/g, awsAccessKeyId)
4057
.replace(/%POLICY_BASE64%/g, policyB64)
58+
.replace(/%CREDENTIAL%/g, credentials)
59+
.replace(/%DATE%/g, `${date}T000000Z`)
4160
.replace(/%SIGNATURE%/g, signature);
4261

4362
fs.writeFile('frontend/index.html', data, 'utf8', (e) => {

aws-node-upload-to-s3-and-postprocess/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
"author": "Christoph Gysin <[email protected]>",
66
"license": "MIT",
77
"dependencies": {
8+
"crypto-js": "^4.0.0"
89
}
910
}

0 commit comments

Comments
 (0)