Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import SHA256 from 'crypto-js/sha256';
- import encHex from 'crypto-js/enc-hex';
- import HmacSHA256 from 'crypto-js/hmac-sha256';
- const sigV4Client = {};
- sigV4Client.newClient = (config) => {
- const AWS_SHA_256 = 'AWS4-HMAC-SHA256';
- const AWS4_REQUEST = 'aws4_request';
- const AWS4 = 'AWS4';
- const X_AMZ_DATE = 'x-amz-date';
- const X_AMZ_SECURITY_TOKEN = 'x-amz-security-token';
- const HOST = 'host';
- const AUTHORIZATION = 'Authorization';
- function hash(value) {
- return SHA256(value); // eslint-disable-line
- }
- function hexEncode(value) {
- return value.toString(encHex);
- }
- function hmac(secret, value) {
- return HmacSHA256(value, secret, { asBytes: true }); // eslint-disable-line
- }
- function buildCanonicalRequest(method, path, queryParams, headers, payload) {
- const bPath = buildCanonicalUri(path);
- const bParams = buildCanonicalQueryString(queryParams);
- const bHeaders = buildCanonicalHeaders(headers);
- const bSHeaders = buildCanonicalSignedHeaders(headers);
- const bPayload = hexEncode(hash(payload));
- return (
- `${method}\n${bPath}\n${bParams}\n${bHeaders}\n${bSHeaders}\n${bPayload}`
- );
- }
- function hashCanonicalRequest(request) {
- return hexEncode(hash(request));
- }
- function buildCanonicalUri(uri) {
- return encodeURI(uri);
- }
- function buildCanonicalQueryString(queryParams) {
- if (Object.keys(queryParams).length < 1) {
- return '';
- }
- const sortedQueryParams = [];
- Object.keys(queryParams).forEach((property) => {
- if (Object.prototype.hasOwnProperty.call(queryParams, property)) {
- sortedQueryParams.push(property);
- }
- });
- sortedQueryParams.sort();
- let canonicalQueryString = '';
- for (let i = 0; i < sortedQueryParams.length; i += 1) {
- canonicalQueryString +=
- `${sortedQueryParams[i]}=${encodeURIComponent(queryParams[sortedQueryParams[i]])}&`;
- }
- return canonicalQueryString.substr(0, canonicalQueryString.length - 1);
- }
- function buildCanonicalHeaders(headers) {
- let canonicalHeaders = '';
- const sortedKeys = [];
- Object.keys(headers).forEach((property) => {
- if (Object.prototype.hasOwnProperty.call(headers, property)) {
- sortedKeys.push(property);
- }
- });
- sortedKeys.sort();
- for (let i = 0; i < sortedKeys.length; i += 1) {
- canonicalHeaders +=
- `${sortedKeys[i].toLowerCase()}:${headers[sortedKeys[i]]}\n`;
- }
- return canonicalHeaders;
- }
- function buildCanonicalSignedHeaders(headers) {
- const sortedKeys = [];
- Object.keys(headers).forEach((property) => {
- if (Object.prototype.hasOwnProperty.call(headers, property)) {
- sortedKeys.push(property.toLowerCase());
- }
- });
- sortedKeys.sort();
- return sortedKeys.join(';');
- }
- function buildStringToSign(
- datetime,
- credentialScope,
- hashedCanonicalRequest
- ) {
- return (
- `${AWS_SHA_256}\n${datetime}\n${credentialScope}\n${hashedCanonicalRequest}`
- );
- }
- function buildCredentialScope(datetime, region, service) {
- return (
- `${datetime.substr(0, 8)}/${region}/${service}/${AWS4_REQUEST}`
- );
- }
- function calculateSigningKey(secretKey, datetime, region, service) {
- return hmac(
- hmac(
- hmac(hmac(AWS4 + secretKey, datetime.substr(0, 8)), region),
- service
- ),
- AWS4_REQUEST
- );
- }
- function calculateSignature(key, stringToSign) {
- return hexEncode(hmac(key, stringToSign));
- }
- function extractHostname(url) {
- let hostname;
- if (url.indexOf('://') > -1) {
- hostname = url.split('/')[2];
- } else {
- hostname = url.split('/')[0];
- }
- hostname = hostname.split(':')[0];
- hostname = hostname.split('?')[0];
- return hostname;
- }
- function buildAuthorizationHeader(
- accessKey,
- credentialScope,
- headers,
- signature
- ) {
- const signedHeaders = buildCanonicalSignedHeaders(headers);
- return (
- `${AWS_SHA_256} Credential=${accessKey}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`
- );
- }
- const awsSigV4Client = {};
- if (config.accessKey === undefined || config.secretKey === undefined) {
- return awsSigV4Client;
- }
- awsSigV4Client.accessKey = config.accessKey;
- awsSigV4Client.secretKey = config.secretKey;
- awsSigV4Client.sessionToken = config.sessionToken;
- awsSigV4Client.serviceName = config.serviceName || 'execute-api';
- awsSigV4Client.region = config.region || 'us-east-1';
- awsSigV4Client.defaultAcceptType =
- config.defaultAcceptType || 'application/json';
- awsSigV4Client.defaultContentType =
- config.defaultContentType || 'application/json';
- const invokeUrl = config.endpoint;
- const endpoint = /(^https?:\/\/[^/]+)/g.exec(invokeUrl)[1];
- const pathComponent = invokeUrl.substring(endpoint.length);
- awsSigV4Client.endpoint = endpoint;
- awsSigV4Client.pathComponent = pathComponent;
- awsSigV4Client.signRequest = (request) => {
- const verb = request.method.toUpperCase();
- const path = awsSigV4Client.pathComponent + request.path;
- const queryParams = { ...request.queryParams };
- const headers = { ...request.headers };
- // If the user has not specified an override for Content type the use default
- if (headers['Content-Type'] === undefined) {
- headers['Content-Type'] = awsSigV4Client.defaultContentType;
- }
- // If the user has not specified an override for Accept type the use default
- if (headers.Accept === undefined) {
- headers.Accept = awsSigV4Client.defaultAcceptType;
- }
- let body = { ...request.body };
- // override request body and set to empty when signing GET requests
- if (request.body === undefined || verb === 'GET') {
- body = '';
- } else {
- body = JSON.stringify(body);
- }
- // If there is no body remove the content-type header so it is not
- // included in SigV4 calculation
- if (body === '' || body === undefined || body === null) {
- delete headers['Content-Type'];
- }
- const datetime = new Date()
- .toISOString()
- .replace(/\.\d{3}Z$/, 'Z')
- .replace(/[:-]|\.\d{3}/g, '');
- headers[X_AMZ_DATE] = datetime;
- headers[HOST] = extractHostname(awsSigV4Client.endpoint);
- const canonicalRequest = buildCanonicalRequest(
- verb,
- path,
- queryParams,
- headers,
- body
- );
- const hashedCanonicalRequest = hashCanonicalRequest(canonicalRequest);
- const credentialScope = buildCredentialScope(
- datetime,
- awsSigV4Client.region,
- awsSigV4Client.serviceName
- );
- const stringToSign = buildStringToSign(
- datetime,
- credentialScope,
- hashedCanonicalRequest
- );
- const signingKey = calculateSigningKey(
- awsSigV4Client.secretKey,
- datetime,
- awsSigV4Client.region,
- awsSigV4Client.serviceName
- );
- const signature = calculateSignature(signingKey, stringToSign);
- headers[AUTHORIZATION] = buildAuthorizationHeader(
- awsSigV4Client.accessKey,
- credentialScope,
- headers,
- signature
- );
- if (
- awsSigV4Client.sessionToken !== undefined &&
- awsSigV4Client.sessionToken !== ''
- ) {
- headers[X_AMZ_SECURITY_TOKEN] = awsSigV4Client.sessionToken;
- }
- delete headers[HOST];
- let url = awsSigV4Client.endpoint + path;
- const queryString = buildCanonicalQueryString(queryParams);
- if (queryString !== '') {
- url = `${url}?${queryString}`;
- }
- // Need to re-attach Content-Type if it is not specified at this point
- if (headers['Content-Type'] === undefined) {
- headers['Content-Type'] = awsSigV4Client.defaultContentType;
- }
- return {
- headers,
- url,
- };
- };
- return awsSigV4Client;
- };
- export default sigV4Client;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement