How to configure AWS S3 bucket policies so that uploaded files are readable as public files. Could somebody please give an example for node js code?
I am a novice to the field so I do not have prior experience regarding this. Any help is highly appreciated.
CodePudding user response:
You can check out this official documentation of AWS s3 for NodeJS that explains how to update bucket policies
CodePudding user response:
There are several steps in this process.This instructions are applicable for nodejs 14 (runtime: nodejs14.x) First you have to follow the below link format after logging in to your AWS account You should follow the below format. https://s3.console.aws.amazon.com/s3/buckets/{BUCKET-NAME}?region={REGION}&tab=permissions#
This is an example link
https://s3.console.aws.amazon.com/s3/buckets/logo?region=us-east-1&tab=permissions#
image: This is an example of entering the path
Second step is creating bucket policies. Replace the word "BUCKET-NAME" with the name of your bucket.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::BUCKET-NAME/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "public-read"
}
}
}
]
}
image: Bucket policies JSON configuration
Then create an endpoint on serverless.yml following the below code. file_upload function is included in handler.js file.
serverless.yml
file_upload:
handler: handler.file_upload
timeout: 15
events:
- httpApi:
path: /file-upload
method: post
After that you have to program handler.js file as below
handler.js
'use strict';
const AWS = require("aws-sdk");
const s3 = new AWS.S3()
const { Validator } = require('node-input-validator');
const MAX_SIZE = 2097152 // 2MB
const bucket = 'S3_BUCKET-NAME' // Name of your bucket.
const Busboy = require("busboy")
s3.config.update({
region: "us-east-1",
accessKeyId: 'S3_ACCESS_KEY_ID',
secretAccessKey: 'S3_SECRET_ACCESS_KEY'
});
const sendJSON = (code, message, data) => {
let resData = {
"status": code < 400 ? 'Success' : 'Error',
"message": message,
}
data ? (resData["data"] = data) : null;
return {
statusCode: code,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
...resData
})
};
}
const FORM = {
parse(body, headers) {
return new Promise((resolve, reject) => {
const data = {};
const buffer = Buffer.from(body, 'base64');
const bb = Busboy({
headers: Object.keys(headers).reduce((newHeaders, key) => {
// busboy expects lower-case headers.
newHeaders[key.toLowerCase()] = headers[key];
return newHeaders;
}, {}),
limits: {
fileSize: MAX_SIZE, // Set as desired.
files: 1,
},
});
bb.on('file', (name, stream, info) => {
const chunks = [];
stream.on('data', (chunk) => {
if (name === 'File') {
chunks.push(chunk);
} else {
reject(new Error('File not found.'));
}
}).on('limit', () => {
reject(new Error('File size limit has been reached.'));
}).on('close', () => {
if (name === 'File') {
data[name] = Buffer.concat(chunks);
data['ContentType'] = info.mimeType;
data['FileName'] = info.filename;
}
});
});
bb.on('field', (name, val, info) => {
data[name] = val;
});
bb.on('error', (err) => {
reject(err);
});
bb.on('close', () => {
resolve(data);
});
bb.end(buffer);
});
}
};
const uploadToS3 = (bucket, key, buffer, mimeType) =>
new Promise((resolve, reject) => {
s3.upload(
{ Bucket: bucket, Key: key, Body: buffer, ContentType: mimeType, ACL: 'public-read' },
function (err, data) {
if (err) reject(err);
resolve(data)
})
});
module.exports.file_upload = async (event) => {
try {
const data = await FORM.parse(event['body'], event['headers']);
const validations = new Validator(data, {
File: 'required'
});
const.path = data.path? data.path : null;
const matched = await validations.check();
if (!matched) {
return sendJSON(400, validations.errors);
}
const date = Math.floor(Date.now() / 1000);
const list = data.FileName.split(".");
const originalKey = `${PATH}/${Date.now()}_${md5(list[0])}.${list[list.length-1]}`; // "PATH" is your sub-folder path in S3.
const originalFile = await Promise.all([
uploadToS3(bucket, originalKey, data.File, data.ContentType)
]);
const file_name = originalFile[0]['Key'];
return sendJSON(201, 'Successfully saved.', originalFile);
} catch (e) {
return sendJSON(400, e.message);
}
};
A link for AWS documentation is attached below
https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html