aws4-axios
Version:
Axios request interceptor for signing requests with AWSv4
166 lines (165 loc) • 7.68 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.aws4Interceptor = void 0;
const aws4_1 = require("aws4");
const axios_1 = __importStar(require("axios"));
const assumeRoleCredentialsProvider_1 = require("./credentials/assumeRoleCredentialsProvider");
const isCredentialsProvider_1 = require("./credentials/isCredentialsProvider");
const simpleCredentialsProvider_1 = require("./credentials/simpleCredentialsProvider");
const crypto_1 = require("crypto");
const removeUndefined = (obj) => {
const newObj = {};
for (const [key, value] of Object.entries(obj)) {
if (value !== undefined) {
newObj[key] = value;
}
}
return newObj;
};
/**
* Create an interceptor to add to the Axios request chain. This interceptor
* will sign requests with the AWSv4 signature.
*
* @example
* axios.interceptors.request.use(
* aws4Interceptor({ region: "eu-west-2", service: "execute-api" })
* );
*
* @param options The options to be used when signing a request
* @param credentials Credentials to be used to sign the request
*/
// this would be a breaking change to the API
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const aws4Interceptor = ({ instance = axios_1.default, credentials, options, }) => {
let credentialsProvider;
if ((0, isCredentialsProvider_1.isCredentialsProvider)(credentials)) {
credentialsProvider = credentials;
}
else if ((options === null || options === void 0 ? void 0 : options.assumeRoleArn) && !credentials) {
credentialsProvider = new assumeRoleCredentialsProvider_1.AssumeRoleCredentialsProvider({
roleArn: options.assumeRoleArn,
region: options.region,
expirationMarginSec: options.assumedRoleExpirationMarginSec,
roleSessionName: options.assumeRoleSessionName,
});
}
else {
credentialsProvider = new simpleCredentialsProvider_1.SimpleCredentialsProvider(credentials);
}
return (config) => __awaiter(void 0, void 0, void 0, function* () {
const url = instance.getUri(config);
if (!url) {
throw new Error("No URL present in request config, unable to sign request");
}
const { host, pathname, search } = new URL(url);
const { data, method } = config;
const transformRequest = getTransformer(config);
transformRequest.bind(config);
// Save, and reset headers on retry
if (config._originalHeaders) {
config.headers = new axios_1.AxiosHeaders(config._originalHeaders);
}
else {
config._originalHeaders = new axios_1.AxiosHeaders(config.headers);
}
const headers = config.headers;
// @ts-expect-error we bound the function to the config object
const transformedData = transformRequest(data, headers);
// Remove all the default Axios headers
const _a = headers, { common, delete: _delete, // 'delete' is a reserved word
get, head, post, put, patch } = _a, headersToSign = __rest(_a, ["common", "delete", "get", "head", "post", "put", "patch"]);
// Axios type definitions do not match the real shape of this object
const signingOptions = {
method: method && method.toUpperCase(),
host,
path: pathname + search,
region: options === null || options === void 0 ? void 0 : options.region,
service: options === null || options === void 0 ? void 0 : options.service,
signQuery: options === null || options === void 0 ? void 0 : options.signQuery,
body: transformedData,
headers: removeUndefined(headersToSign),
};
const resolvedCredentials = yield credentialsProvider.getCredentials();
(0, aws4_1.sign)(signingOptions, resolvedCredentials);
if (signingOptions.headers) {
for (const [key, value] of Object.entries(signingOptions.headers)) {
config.headers.set(key, value);
}
}
if (signingOptions.signQuery) {
const originalUrl = new URL(url);
const signedUrl = new URL(originalUrl.origin + signingOptions.path);
config.params = Object.assign(Object.assign({}, config.params), Object.fromEntries(signedUrl.searchParams.entries()));
}
if (options === null || options === void 0 ? void 0 : options.addContentSha) {
config.headers.set('X-Amz-Content-Sha256', (0, crypto_1.createHash)('sha256').update(transformedData !== null && transformedData !== void 0 ? transformedData : '', 'utf8').digest('hex'));
}
return config;
});
};
exports.aws4Interceptor = aws4Interceptor;
const getTransformer = (config) => {
const { transformRequest } = config;
if (transformRequest) {
if (typeof transformRequest === "function") {
return transformRequest;
}
else if (transformRequest.length) {
return transformRequest[0];
}
}
throw new Error("Could not get default transformRequest function from Axios defaults");
};
;