💾 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
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
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;