Anyone who was able to sign AWS requests (SigV4) from xano?

Options

I need to call the AWS lambda functional URL directly. I do not want to have one API gateway in front of my AWS lambda to save cost. Signing AWS URLs with SigV4 requires a series of steps but I think someone may have already replicated these steps in xano. Can anyone share the snippet? This will save a ton of time.

(https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html)

@Michael Udinski , @xano team, I think this is something if available in the marketplace/inbuild functions will be very helpful for the community. I am not able to find one right now. Do you guys have any plans to add AWS SigV4 functionality soon?


Why I had to write a Lambda function?

This AWS Lambda function can generate PDF using input HTML string or from HTML file from another s3 bucket and then store it in the target s3 bucket. I have decided to go through this approach as PDF creation APIs were just too costly for me and I think there is no direct way to do this in xano. We send order estimates, order summaries, etc to our customers via downloadable PDF URLs, which are stored in an s3 bucket. This is currently being done in a bubble through a free PDF plugin available there. So if there is an alternate cheap way to generate PDF files and store them in an s3 bucket with xano I am open to exploring that option as well.

Tagged:

Comments

  • Future
    Options

    Same boat... Made a request here : https://xano.nolt.io/175

    Still banging my head every time I need to use an AWS (or AWS compatible) service.

  • Brandon Hassler
    Brandon Hassler Member
    edited December 2022
    Options

    Adding a big "AMEN" to the ability for Xano to have some type of snippet/template to accomplish this without writing it all from scratch. I'm not sure if this is the type of stuff @brian will be potentially tackling but boy oh boy would a V4 signature snippet be amazing to have. I've been very close to getting it to work as I've tackled it with some expert help but I ended up getting very busy with other projects and have been paying a premium to a 3rd party data company to get the same data I could be getting for free directly through Amazon's PAAPI 5.0. They do have SDK's like @Future mentioned in their request, but Xano currently doesn't support them. Although back in October @Michael Udinski had mentioned this is something that will be possible when Xano rolls out access to all npm libraries. No release date has been mentioned, but I'm crossing my fingers that we are close because (at least for Amazon's Product API) being able to use their SDK library should be just as good as a prebuilt snippet and for my business that will be HUGE since I run a price comparison website and paying for those prices through 3rd party vendors isn't cheap.

  • brian
    brian Administrator

    ADMIN

    Options

    I'll look into it @Brandon Hassler!

  • Future
    Options

    Well... if someone ever gets the way to generate presigned url's for s3 compatible storage... Don't hesitate to share lol.. I've been stuck on this for a few days and can't manage to make a custom function work.


    Here's what i'm basing my work on if it can help someone... (found on github)

    //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 = crypto.Crypto;
    
    
    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;
    }