Created
July 27, 2017 17:02
-
-
Save adv0r/1dfaf7999d7aac95d473e65b675496b0 to your computer and use it in GitHub Desktop.
AWS s3 : Generate a pre-signed URL - step-by-step. {Node.js}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//A quick way to generate valid URL to GET files hosted on private AWS S3 bucket | |
//I didn't want to use an SKD so I followed the documentation to make my own and learn | |
//The code is dirty, but since I couln't find anything online, | |
//I figured this could be handy to someone | |
//Requirements : Node and Crypto-js (install with npm install crypto-js) | |
//Remote settings----------------------------------------------------------- | |
var regionName = "eu-central-1"; //Replace with your correct AWS region | |
var bucketName = "your-bucket-name "; //replace with your bucket name | |
var testFilePath = "path/to/file.ext"; //replace with the file path you want to GET | |
//AWS Credentials | |
var accessKey = "AKEXAMPLEKEY"; //Replace with your Access Key | |
var secretKey = "dasodpsoakdsakdasuidhsaiudusa"; //Replace with your Secret Key | |
//Settings ----------------------------------------------------------------- | |
var sep = "%2F"; // Used to encode the '/' | |
var serviceName = "s3"; | |
var expiration = "86400" //The generate url will be valid for 24 hours from the current date; | |
var baseUrl = "https://"+bucketName+".s3.amazonaws.com/"; | |
//Use crypto-js library to perform SHA256 | |
var crypto = require("crypto-js"); | |
prepareRequest(crypto); //Execute this on startup | |
//Prepare request | |
function prepareRequest(){ | |
var resourceUrl = baseUrl+testFilePath; | |
console.log("Step 1 - Obtain the base URL : "+resourceUrl); | |
var longDate = getCurrentDate(); //yyyyMMddTHHmmssZ | |
var shortDate = longDate.substring(0,8); // yyyyMMdd | |
console.log("Step 2 - Obtain the current date in both long ["+longDate+"] and shorter ["+shortDate+"] format"); | |
var queryParmeters = getQueryParameters(longDate,shortDate); | |
console.log("Step 3 - : Obtain the query parameters : "+queryParmeters); | |
var canonicalRequest = getCanonicalRequest(queryParmeters); | |
console.log("Step 4 - Obtain the CanonicalRequest : "+canonicalRequest); | |
var messaggeToSign = getStringToSign(crypto,canonicalRequest,longDate,shortDate); | |
console.log("Step 5 - Obtain the StringToSign : "+messaggeToSign); | |
var signignKey = getSignatureKey(crypto,secretKey,shortDate,regionName,serviceName); | |
console.log("Step 6 - Obtain the signing key : "+signignKey); | |
var signature = getSignature(crypto,messaggeToSign,signignKey); | |
console.log("Step 7 - Obtain the signature to append to query parameters : "+signature); | |
var authorizedUrl = getAuthorizedUrl(resourceUrl,queryParmeters,signature); | |
console.log("Step 8 - Obtain the valid URL to get the file : "+authorizedUrl); | |
} | |
//_______________________________________Functions | |
function getCurrentDate(){ // | |
return new Date().toISOString(). //'2012-11-04T14:51:06.157Z' | |
replace(/-/g, ''). // replace dashes with empty char '20121104T14:51:06.157Z' | |
replace(/:/g, ''). // replace column with empty char '20121104T145106.157Z' | |
replace(/\..+/, '') // delete the dot and everything after '20121104T145106' | |
+'Z' ; //re-add Z for UTC '20121104T145106Z' | |
} | |
function getQueryParameters(longDate,shortDate){ | |
var queryParmeters = "X-Amz-Algorithm=AWS4-HMAC-SHA256"+ | |
"&X-Amz-Credential="+accessKey+sep+shortDate+sep+regionName+sep+serviceName+sep+"aws4_request"+ | |
"&X-Amz-Date="+longDate+ | |
"&X-Amz-Expires="+expiration+ | |
"&X-Amz-SignedHeaders=host"; | |
return queryParmeters; | |
} | |
function getCanonicalRequest(queryParmeters){ | |
var canonicalRequest = "GET" + "\n" + | |
"/"+testFilePath + "\n" + | |
AWSUriEncode(queryParmeters) + "\n" + | |
"host:"+bucketName+".s3.amazonaws.com" + "\n\n" + | |
"host"+ "\n" + | |
"UNSIGNED-PAYLOAD"; | |
return canonicalRequest; | |
} | |
function getStringToSign(Crypto,canonicalRequest,longDate,shortDate){ | |
var stringToSign = "AWS4-HMAC-SHA256\n" + | |
longDate + "\n" + | |
shortDate + "/"+ regionName + "/" +serviceName +"/aws4_request\n" + | |
Crypto.SHA256(canonicalRequest); //Compute HASH of CanonicalRequest | |
return stringToSign; | |
} | |
function getSignature(Crypto,message,key){ | |
var kSignature = Crypto.HmacSHA256(message, key); | |
return kSignature.toString(); | |
} | |
function getSignatureKey(Crypto, secret, date, regionName, serviceName) { | |
var message = date; | |
var key = "AWS4" + secret; | |
var kDate = Crypto.HmacSHA256(message, key); | |
//console.log("First salt : Message = "+message+ " , key = "+key + " , result = " + kDate); | |
message = regionName; | |
key = kDate.toString(); | |
var kRegion = Crypto.HmacSHA256(message, key); | |
//console.log("Second salt : Message = "+message+ " , key = "+key + " , result = " + kRegion); | |
message = serviceName; | |
key = kRegion; | |
var kService = Crypto.HmacSHA256(message, key); | |
//console.log("Third salt : Message = "+message+ " , key = "+key + " , result = " + kService); | |
message = "aws4_request"; | |
key = kService; | |
var kSigning = Crypto.HmacSHA256(message, key); | |
//console.log("Fourth salt : Message = "+message+ " , key = "+key + " , result = " + kSigning); | |
return kSigning; | |
} | |
function getAuthorizedUrl(path,queryParmeters,signature){ | |
var authorizedUrl = path+"?"+ | |
queryParmeters+ | |
"&X-Amz-Signature="+signature; | |
return authorizedUrl; | |
} | |
//TODO improve this function and make it complaint with amazon AWS docs | |
function AWSUriEncode(inputString){ | |
var outputString = inputString.replace(/\//g,sep); | |
return outputString; | |
} |
Here's AWS API v4 documentation being referred to in the snippets in case anyone wants it. https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
Hi what is testfilePath variable here? I am not clear to this, is this "credential" file found under :C/users/username/.aws folder?
are you creating any lambda functions here? or APIgateway ?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also: https://stackoverflow.com/questions/38831829/nodejs-aws-sdk-s3-generate-presigned-url