Advertisement
Guest User

Untitled

a guest
Jul 18th, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import SHA256 from 'crypto-js/sha256';
  2. import encHex from 'crypto-js/enc-hex';
  3. import HmacSHA256 from 'crypto-js/hmac-sha256';
  4.  
  5. const sigV4Client = {};
  6. sigV4Client.newClient = (config) => {
  7.   const AWS_SHA_256 = 'AWS4-HMAC-SHA256';
  8.   const AWS4_REQUEST = 'aws4_request';
  9.   const AWS4 = 'AWS4';
  10.   const X_AMZ_DATE = 'x-amz-date';
  11.   const X_AMZ_SECURITY_TOKEN = 'x-amz-security-token';
  12.   const HOST = 'host';
  13.   const AUTHORIZATION = 'Authorization';
  14.  
  15.   function hash(value) {
  16.     return SHA256(value); // eslint-disable-line
  17.   }
  18.  
  19.   function hexEncode(value) {
  20.     return value.toString(encHex);
  21.   }
  22.  
  23.   function hmac(secret, value) {
  24.     return HmacSHA256(value, secret, { asBytes: true }); // eslint-disable-line
  25.   }
  26.  
  27.   function buildCanonicalRequest(method, path, queryParams, headers, payload) {
  28.     const bPath = buildCanonicalUri(path);
  29.     const bParams = buildCanonicalQueryString(queryParams);
  30.     const bHeaders = buildCanonicalHeaders(headers);
  31.     const bSHeaders = buildCanonicalSignedHeaders(headers);
  32.     const bPayload = hexEncode(hash(payload));
  33.     return (
  34.       `${method}\n${bPath}\n${bParams}\n${bHeaders}\n${bSHeaders}\n${bPayload}`
  35.     );
  36.   }
  37.  
  38.   function hashCanonicalRequest(request) {
  39.     return hexEncode(hash(request));
  40.   }
  41.  
  42.   function buildCanonicalUri(uri) {
  43.     return encodeURI(uri);
  44.   }
  45.  
  46.   function buildCanonicalQueryString(queryParams) {
  47.     if (Object.keys(queryParams).length < 1) {
  48.       return '';
  49.     }
  50.  
  51.     const sortedQueryParams = [];
  52.  
  53.     Object.keys(queryParams).forEach((property) => {
  54.       if (Object.prototype.hasOwnProperty.call(queryParams, property)) {
  55.         sortedQueryParams.push(property);
  56.       }
  57.     });
  58.     sortedQueryParams.sort();
  59.  
  60.     let canonicalQueryString = '';
  61.     for (let i = 0; i < sortedQueryParams.length; i += 1) {
  62.       canonicalQueryString +=
  63.         `${sortedQueryParams[i]}=${encodeURIComponent(queryParams[sortedQueryParams[i]])}&`;
  64.     }
  65.     return canonicalQueryString.substr(0, canonicalQueryString.length - 1);
  66.   }
  67.  
  68.   function buildCanonicalHeaders(headers) {
  69.     let canonicalHeaders = '';
  70.     const sortedKeys = [];
  71.     Object.keys(headers).forEach((property) => {
  72.       if (Object.prototype.hasOwnProperty.call(headers, property)) {
  73.         sortedKeys.push(property);
  74.       }
  75.     });
  76.     sortedKeys.sort();
  77.  
  78.     for (let i = 0; i < sortedKeys.length; i += 1) {
  79.       canonicalHeaders +=
  80.         `${sortedKeys[i].toLowerCase()}:${headers[sortedKeys[i]]}\n`;
  81.     }
  82.     return canonicalHeaders;
  83.   }
  84.  
  85.   function buildCanonicalSignedHeaders(headers) {
  86.     const sortedKeys = [];
  87.     Object.keys(headers).forEach((property) => {
  88.       if (Object.prototype.hasOwnProperty.call(headers, property)) {
  89.         sortedKeys.push(property.toLowerCase());
  90.       }
  91.     });
  92.     sortedKeys.sort();
  93.  
  94.     return sortedKeys.join(';');
  95.   }
  96.  
  97.   function buildStringToSign(
  98.     datetime,
  99.     credentialScope,
  100.     hashedCanonicalRequest
  101.   ) {
  102.     return (
  103.       `${AWS_SHA_256}\n${datetime}\n${credentialScope}\n${hashedCanonicalRequest}`
  104.     );
  105.   }
  106.  
  107.   function buildCredentialScope(datetime, region, service) {
  108.     return (
  109.       `${datetime.substr(0, 8)}/${region}/${service}/${AWS4_REQUEST}`
  110.     );
  111.   }
  112.  
  113.   function calculateSigningKey(secretKey, datetime, region, service) {
  114.     return hmac(
  115.       hmac(
  116.         hmac(hmac(AWS4 + secretKey, datetime.substr(0, 8)), region),
  117.         service
  118.       ),
  119.       AWS4_REQUEST
  120.     );
  121.   }
  122.  
  123.   function calculateSignature(key, stringToSign) {
  124.     return hexEncode(hmac(key, stringToSign));
  125.   }
  126.  
  127.   function extractHostname(url) {
  128.     let hostname;
  129.  
  130.     if (url.indexOf('://') > -1) {
  131.       hostname = url.split('/')[2];
  132.     } else {
  133.       hostname = url.split('/')[0];
  134.     }
  135.  
  136.     hostname = hostname.split(':')[0];
  137.     hostname = hostname.split('?')[0];
  138.  
  139.     return hostname;
  140.   }
  141.  
  142.   function buildAuthorizationHeader(
  143.     accessKey,
  144.     credentialScope,
  145.     headers,
  146.     signature
  147.   ) {
  148.     const signedHeaders = buildCanonicalSignedHeaders(headers);
  149.     return (
  150.       `${AWS_SHA_256} Credential=${accessKey}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`
  151.     );
  152.   }
  153.  
  154.   const awsSigV4Client = {};
  155.   if (config.accessKey === undefined || config.secretKey === undefined) {
  156.     return awsSigV4Client;
  157.   }
  158.   awsSigV4Client.accessKey = config.accessKey;
  159.   awsSigV4Client.secretKey = config.secretKey;
  160.   awsSigV4Client.sessionToken = config.sessionToken;
  161.   awsSigV4Client.serviceName = config.serviceName || 'execute-api';
  162.   awsSigV4Client.region = config.region || 'us-east-1';
  163.   awsSigV4Client.defaultAcceptType =
  164.     config.defaultAcceptType || 'application/json';
  165.   awsSigV4Client.defaultContentType =
  166.     config.defaultContentType || 'application/json';
  167.  
  168.   const invokeUrl = config.endpoint;
  169.   const endpoint = /(^https?:\/\/[^/]+)/g.exec(invokeUrl)[1];
  170.   const pathComponent = invokeUrl.substring(endpoint.length);
  171.  
  172.   awsSigV4Client.endpoint = endpoint;
  173.   awsSigV4Client.pathComponent = pathComponent;
  174.  
  175.   awsSigV4Client.signRequest = (request) => {
  176.     const verb = request.method.toUpperCase();
  177.     const path = awsSigV4Client.pathComponent + request.path;
  178.     const queryParams = { ...request.queryParams };
  179.     const headers = { ...request.headers };
  180.  
  181.     // If the user has not specified an override for Content type the use default
  182.     if (headers['Content-Type'] === undefined) {
  183.       headers['Content-Type'] = awsSigV4Client.defaultContentType;
  184.     }
  185.  
  186.     // If the user has not specified an override for Accept type the use default
  187.     if (headers.Accept === undefined) {
  188.       headers.Accept = awsSigV4Client.defaultAcceptType;
  189.     }
  190.  
  191.     let body = { ...request.body };
  192.     // override request body and set to empty when signing GET requests
  193.     if (request.body === undefined || verb === 'GET') {
  194.       body = '';
  195.     } else {
  196.       body = JSON.stringify(body);
  197.     }
  198.  
  199.     // If there is no body remove the content-type header so it is not
  200.     // included in SigV4 calculation
  201.     if (body === '' || body === undefined || body === null) {
  202.       delete headers['Content-Type'];
  203.     }
  204.  
  205.     const datetime = new Date()
  206.       .toISOString()
  207.       .replace(/\.\d{3}Z$/, 'Z')
  208.       .replace(/[:-]|\.\d{3}/g, '');
  209.     headers[X_AMZ_DATE] = datetime;
  210.     headers[HOST] = extractHostname(awsSigV4Client.endpoint);
  211.  
  212.     const canonicalRequest = buildCanonicalRequest(
  213.       verb,
  214.       path,
  215.       queryParams,
  216.       headers,
  217.       body
  218.     );
  219.     const hashedCanonicalRequest = hashCanonicalRequest(canonicalRequest);
  220.     const credentialScope = buildCredentialScope(
  221.       datetime,
  222.       awsSigV4Client.region,
  223.       awsSigV4Client.serviceName
  224.     );
  225.     const stringToSign = buildStringToSign(
  226.       datetime,
  227.       credentialScope,
  228.       hashedCanonicalRequest
  229.     );
  230.     const signingKey = calculateSigningKey(
  231.       awsSigV4Client.secretKey,
  232.       datetime,
  233.       awsSigV4Client.region,
  234.       awsSigV4Client.serviceName
  235.     );
  236.     const signature = calculateSignature(signingKey, stringToSign);
  237.     headers[AUTHORIZATION] = buildAuthorizationHeader(
  238.       awsSigV4Client.accessKey,
  239.       credentialScope,
  240.       headers,
  241.       signature
  242.     );
  243.     if (
  244.       awsSigV4Client.sessionToken !== undefined &&
  245.       awsSigV4Client.sessionToken !== ''
  246.     ) {
  247.       headers[X_AMZ_SECURITY_TOKEN] = awsSigV4Client.sessionToken;
  248.     }
  249.     delete headers[HOST];
  250.  
  251.     let url = awsSigV4Client.endpoint + path;
  252.     const queryString = buildCanonicalQueryString(queryParams);
  253.     if (queryString !== '') {
  254.       url = `${url}?${queryString}`;
  255.     }
  256.  
  257.     // Need to re-attach Content-Type if it is not specified at this point
  258.     if (headers['Content-Type'] === undefined) {
  259.       headers['Content-Type'] = awsSigV4Client.defaultContentType;
  260.     }
  261.  
  262.     return {
  263.       headers,
  264.       url,
  265.     };
  266.   };
  267.  
  268.   return awsSigV4Client;
  269. };
  270.  
  271. export default sigV4Client;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement