Created
March 17, 2019 11:47
-
-
Save i-like-robots/8913dad2204f95f0d4044b338092a584 to your computer and use it in GitHub Desktop.
Signed AWS requests with node fetch
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
const nodeFetch = require('node-fetch'); | |
const httpsAgent = require('./httpsAgent'); | |
const handleResponse = require('./handleResponse'); | |
module.exports = async (url, options = {}) => { | |
const response = await nodeFetch(url, { | |
...options, | |
agent: httpsAgent | |
}); | |
return handleResponse(response); | |
}; |
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
module.exports = (response) => { | |
if (response.ok) { | |
const contentType = response.headers.get('content-type'); | |
if (contentType && contentType.includes('application/json')) { | |
return response.json(); | |
} else { | |
return response.text(); | |
} | |
} else { | |
throw Error(`Request to ${response.url} responded with a ${response.status}`); | |
} | |
}; |
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
const https = require('https'); | |
module.exports = new https.Agent({ keepAlive: true }); |
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
const aws4 = require('aws4'); | |
const { URL } = require('url'); | |
const fetch = require('./fetch'); | |
const resolveCname = require('./resolveCname'); | |
module.exports = async (url, options = {}, credentials = {}) => { | |
const parsedURL = new URL(url); | |
// Ensure we sign the actual service URL and not a load balancer URL | |
const hostname = await resolveCname(parsedURL.host); | |
const signedOptions = { | |
method: options.method, | |
host: hostname, | |
path: parsedURL.pathname + parsedURL.search, | |
body: options.body, | |
headers: options.headers | |
}; | |
aws4.sign(signedOptions, { | |
accessKeyId: credentials.awsAccessKey, | |
secretAccessKey: credentials.awsSecretAccessKey | |
}); | |
options.headers = signedOptions.headers; | |
return fetch(`https://${signedOptions.host}${signedOptions.path}`, options); | |
}; |
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
{ | |
"name": "signed-aws-fetch", | |
"version": "1.0.0", | |
"description": "", | |
"engines": { | |
"node": ">= 8.0.0" | |
}, | |
"main": "index.js", | |
"dependencies": { | |
"aws4": "^1.8.0", | |
"lru-cache": "^5.1.0", | |
"node-fetch": "^2.3.0" | |
}, | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "Matt Hinchliffe", | |
"license": "ISC" | |
} |
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
const dns = require('dns'); | |
const util = require('util'); | |
const LRU = require('lru-cache'); | |
const cache = new LRU({ maxAge: 1000 * 60, stale: true }); | |
const resolveCname = util.promisify(dns.resolveCname); | |
module.exports = async (domain) => { | |
if (/\.amazonaws\.com$/.test(domain)) { | |
return domain; | |
} | |
if (cache.has(domain)) { | |
return cache.get(domain); | |
} | |
const [ resolvedName ] = await resolveCname(domain); | |
if (resolvedName) { | |
cache.set(domain, resolvedName); | |
return resolvedName; | |
} else { | |
throw Error(`Could not resolve CNAME for ${domain}`); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment