💾 Archived View for gmi.noulin.net › gitRepositories › git-off › file › src › node_modules › aws-sdk… captured on 2024-09-29 at 00:46:01. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

git-off

Log

Files

Refs

README

v4.js (7575B)

     1 var AWS = require('../core');
     2 var inherit = AWS.util.inherit;
     3 
     4 /**
     5  * @api private
     6  */
     7 var cachedSecret = {};
     8 
     9 /**
    10  * @api private
    11  */
    12 var cacheQueue = [];
    13 
    14 /**
    15  * @api private
    16  */
    17 var maxCacheEntries = 50;
    18 
    19 /**
    20  * @api private
    21  */
    22 var expiresHeader = 'presigned-expires';
    23 
    24 /**
    25  * @api private
    26  */
    27 AWS.Signers.V4 = inherit(AWS.Signers.RequestSigner, {
    28   constructor: function V4(request, serviceName, signatureCache) {
    29     AWS.Signers.RequestSigner.call(this, request);
    30     this.serviceName = serviceName;
    31     this.signatureCache = signatureCache;
    32   },
    33 
    34   algorithm: 'AWS4-HMAC-SHA256',
    35 
    36   addAuthorization: function addAuthorization(credentials, date) {
    37     var datetime = AWS.util.date.iso8601(date).replace(/[:\-]|\.\d{3}/g, '');
    38 
    39     if (this.isPresigned()) {
    40       this.updateForPresigned(credentials, datetime);
    41     } else {
    42       this.addHeaders(credentials, datetime);
    43     }
    44 
    45     this.request.headers['Authorization'] =
    46       this.authorization(credentials, datetime);
    47   },
    48 
    49   addHeaders: function addHeaders(credentials, datetime) {
    50     this.request.headers['X-Amz-Date'] = datetime;
    51     if (credentials.sessionToken) {
    52       this.request.headers['x-amz-security-token'] = credentials.sessionToken;
    53     }
    54   },
    55 
    56   updateForPresigned: function updateForPresigned(credentials, datetime) {
    57     var credString = this.credentialString(datetime);
    58     var qs = {
    59       'X-Amz-Date': datetime,
    60       'X-Amz-Algorithm': this.algorithm,
    61       'X-Amz-Credential': credentials.accessKeyId + '/' + credString,
    62       'X-Amz-Expires': this.request.headers[expiresHeader],
    63       'X-Amz-SignedHeaders': this.signedHeaders()
    64     };
    65 
    66     if (credentials.sessionToken) {
    67       qs['X-Amz-Security-Token'] = credentials.sessionToken;
    68     }
    69 
    70     if (this.request.headers['Content-Type']) {
    71       qs['Content-Type'] = this.request.headers['Content-Type'];
    72     }
    73     if (this.request.headers['Content-MD5']) {
    74       qs['Content-MD5'] = this.request.headers['Content-MD5'];
    75     }
    76     if (this.request.headers['Cache-Control']) {
    77       qs['Cache-Control'] = this.request.headers['Cache-Control'];
    78     }
    79 
    80     // need to pull in any other X-Amz-* headers
    81     AWS.util.each.call(this, this.request.headers, function(key, value) {
    82       if (key === expiresHeader) return;
    83       if (this.isSignableHeader(key)) {
    84         var lowerKey = key.toLowerCase();
    85         // Metadata should be normalized
    86         if (lowerKey.indexOf('x-amz-meta-') === 0) {
    87           qs[lowerKey] = value;
    88         } else if (lowerKey.indexOf('x-amz-') === 0) {
    89           qs[key] = value;
    90         }
    91       }
    92     });
    93 
    94     var sep = this.request.path.indexOf('?') >= 0 ? '&' : '?';
    95     this.request.path += sep + AWS.util.queryParamsToString(qs);
    96   },
    97 
    98   authorization: function authorization(credentials, datetime) {
    99     var parts = [];
   100     var credString = this.credentialString(datetime);
   101     parts.push(this.algorithm + ' Credential=' +
   102       credentials.accessKeyId + '/' + credString);
   103     parts.push('SignedHeaders=' + this.signedHeaders());
   104     parts.push('Signature=' + this.signature(credentials, datetime));
   105     return parts.join(', ');
   106   },
   107 
   108   signature: function signature(credentials, datetime) {
   109     var cache = null;
   110     var cacheIdentifier = this.serviceName + (this.getServiceClientId() ? '_' + this.getServiceClientId() : '');
   111     if (this.signatureCache) {
   112       var cache = cachedSecret[cacheIdentifier];
   113       // If there isn't already a cache entry, we'll be adding one
   114       if (!cache) {
   115         cacheQueue.push(cacheIdentifier);
   116         if (cacheQueue.length > maxCacheEntries) {
   117           // remove the oldest entry (may not be last one used)
   118           delete cachedSecret[cacheQueue.shift()];
   119         }
   120       }
   121 
   122     }
   123     var date = datetime.substr(0, 8);
   124 
   125     if (!cache ||
   126         cache.akid !== credentials.accessKeyId ||
   127         cache.region !== this.request.region ||
   128         cache.date !== date) {
   129 
   130       var kSecret = credentials.secretAccessKey;
   131       var kDate = AWS.util.crypto.hmac('AWS4' + kSecret, date, 'buffer');
   132       var kRegion = AWS.util.crypto.hmac(kDate, this.request.region, 'buffer');
   133       var kService = AWS.util.crypto.hmac(kRegion, this.serviceName, 'buffer');
   134       var kCredentials = AWS.util.crypto.hmac(kService, 'aws4_request', 'buffer');
   135 
   136       if (!this.signatureCache) {
   137         return AWS.util.crypto.hmac(kCredentials, this.stringToSign(datetime), 'hex');
   138       }
   139 
   140       cachedSecret[cacheIdentifier] = {
   141         region: this.request.region, date: date,
   142         key: kCredentials, akid: credentials.accessKeyId
   143       };
   144     }
   145 
   146     var key = cachedSecret[cacheIdentifier].key;
   147     return AWS.util.crypto.hmac(key, this.stringToSign(datetime), 'hex');
   148   },
   149 
   150   stringToSign: function stringToSign(datetime) {
   151     var parts = [];
   152     parts.push('AWS4-HMAC-SHA256');
   153     parts.push(datetime);
   154     parts.push(this.credentialString(datetime));
   155     parts.push(this.hexEncodedHash(this.canonicalString()));
   156     return parts.join('\n');
   157   },
   158 
   159   canonicalString: function canonicalString() {
   160     var parts = [], pathname = this.request.pathname();
   161     if (this.serviceName !== 's3') pathname = AWS.util.uriEscapePath(pathname);
   162 
   163     parts.push(this.request.method);
   164     parts.push(pathname);
   165     parts.push(this.request.search());
   166     parts.push(this.canonicalHeaders() + '\n');
   167     parts.push(this.signedHeaders());
   168     parts.push(this.hexEncodedBodyHash());
   169     return parts.join('\n');
   170   },
   171 
   172   canonicalHeaders: function canonicalHeaders() {
   173     var headers = [];
   174     AWS.util.each.call(this, this.request.headers, function (key, item) {
   175       headers.push([key, item]);
   176     });
   177     headers.sort(function (a, b) {
   178       return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : 1;
   179     });
   180     var parts = [];
   181     AWS.util.arrayEach.call(this, headers, function (item) {
   182       var key = item[0].toLowerCase();
   183       if (this.isSignableHeader(key)) {
   184         parts.push(key + ':' +
   185           this.canonicalHeaderValues(item[1].toString()));
   186       }
   187     });
   188     return parts.join('\n');
   189   },
   190 
   191   canonicalHeaderValues: function canonicalHeaderValues(values) {
   192     return values.replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '');
   193   },
   194 
   195   signedHeaders: function signedHeaders() {
   196     var keys = [];
   197     AWS.util.each.call(this, this.request.headers, function (key) {
   198       key = key.toLowerCase();
   199       if (this.isSignableHeader(key)) keys.push(key);
   200     });
   201     return keys.sort().join(';');
   202   },
   203 
   204   credentialString: function credentialString(datetime) {
   205     var parts = [];
   206     parts.push(datetime.substr(0, 8));
   207     parts.push(this.request.region);
   208     parts.push(this.serviceName);
   209     parts.push('aws4_request');
   210     return parts.join('/');
   211   },
   212 
   213   hexEncodedHash: function hash(string) {
   214     return AWS.util.crypto.sha256(string, 'hex');
   215   },
   216 
   217   hexEncodedBodyHash: function hexEncodedBodyHash() {
   218     if (this.isPresigned() && this.serviceName === 's3' && !this.request.body) {
   219       return 'UNSIGNED-PAYLOAD';
   220     } else if (this.request.headers['X-Amz-Content-Sha256']) {
   221       return this.request.headers['X-Amz-Content-Sha256'];
   222     } else {
   223       return this.hexEncodedHash(this.request.body || '');
   224     }
   225   },
   226 
   227   unsignableHeaders: ['authorization', 'content-type', 'content-length',
   228                       'user-agent', expiresHeader, 'expect'],
   229 
   230   isSignableHeader: function isSignableHeader(key) {
   231     if (key.toLowerCase().indexOf('x-amz-') === 0) return true;
   232     return this.unsignableHeaders.indexOf(key) < 0;
   233   },
   234 
   235   isPresigned: function isPresigned() {
   236     return this.request.headers[expiresHeader] ? true : false;
   237   }
   238 
   239 });
   240 
   241 module.exports = AWS.Signers.V4;