s3.js (4440B)
1 var AWS = require('../core'); 2 var inherit = AWS.util.inherit; 3 4 /** 5 * @api private 6 */ 7 AWS.Signers.S3 = inherit(AWS.Signers.RequestSigner, { 8 /** 9 * When building the stringToSign, these sub resource params should be 10 * part of the canonical resource string with their NON-decoded values 11 */ 12 subResources: { 13 'acl': 1, 14 'accelerate': 1, 15 'cors': 1, 16 'lifecycle': 1, 17 'delete': 1, 18 'location': 1, 19 'logging': 1, 20 'notification': 1, 21 'partNumber': 1, 22 'policy': 1, 23 'requestPayment': 1, 24 'replication': 1, 25 'restore': 1, 26 'tagging': 1, 27 'torrent': 1, 28 'uploadId': 1, 29 'uploads': 1, 30 'versionId': 1, 31 'versioning': 1, 32 'versions': 1, 33 'website': 1 34 }, 35 36 // when building the stringToSign, these querystring params should be 37 // part of the canonical resource string with their NON-encoded values 38 responseHeaders: { 39 'response-content-type': 1, 40 'response-content-language': 1, 41 'response-expires': 1, 42 'response-cache-control': 1, 43 'response-content-disposition': 1, 44 'response-content-encoding': 1 45 }, 46 47 addAuthorization: function addAuthorization(credentials, date) { 48 if (!this.request.headers['presigned-expires']) { 49 this.request.headers['X-Amz-Date'] = AWS.util.date.rfc822(date); 50 } 51 52 if (credentials.sessionToken) { 53 // presigned URLs require this header to be lowercased 54 this.request.headers['x-amz-security-token'] = credentials.sessionToken; 55 } 56 57 var signature = this.sign(credentials.secretAccessKey, this.stringToSign()); 58 var auth = 'AWS ' + credentials.accessKeyId + ':' + signature; 59 60 this.request.headers['Authorization'] = auth; 61 }, 62 63 stringToSign: function stringToSign() { 64 var r = this.request; 65 66 var parts = []; 67 parts.push(r.method); 68 parts.push(r.headers['Content-MD5'] || ''); 69 parts.push(r.headers['Content-Type'] || ''); 70 71 // This is the "Date" header, but we use X-Amz-Date. 72 // The S3 signing mechanism requires us to pass an empty 73 // string for this Date header regardless. 74 parts.push(r.headers['presigned-expires'] || ''); 75 76 var headers = this.canonicalizedAmzHeaders(); 77 if (headers) parts.push(headers); 78 parts.push(this.canonicalizedResource()); 79 80 return parts.join('\n'); 81 82 }, 83 84 canonicalizedAmzHeaders: function canonicalizedAmzHeaders() { 85 86 var amzHeaders = []; 87 88 AWS.util.each(this.request.headers, function (name) { 89 if (name.match(/^x-amz-/i)) 90 amzHeaders.push(name); 91 }); 92 93 amzHeaders.sort(function (a, b) { 94 return a.toLowerCase() < b.toLowerCase() ? -1 : 1; 95 }); 96 97 var parts = []; 98 AWS.util.arrayEach.call(this, amzHeaders, function (name) { 99 parts.push(name.toLowerCase() + ':' + String(this.request.headers[name])); 100 }); 101 102 return parts.join('\n'); 103 104 }, 105 106 canonicalizedResource: function canonicalizedResource() { 107 108 var r = this.request; 109 110 var parts = r.path.split('?'); 111 var path = parts[0]; 112 var querystring = parts[1]; 113 114 var resource = ''; 115 116 if (r.virtualHostedBucket) 117 resource += '/' + r.virtualHostedBucket; 118 119 resource += path; 120 121 if (querystring) { 122 123 // collect a list of sub resources and query params that need to be signed 124 var resources = []; 125 126 AWS.util.arrayEach.call(this, querystring.split('&'), function (param) { 127 var name = param.split('=')[0]; 128 var value = param.split('=')[1]; 129 if (this.subResources[name] || this.responseHeaders[name]) { 130 var subresource = { name: name }; 131 if (value !== undefined) { 132 if (this.subResources[name]) { 133 subresource.value = value; 134 } else { 135 subresource.value = decodeURIComponent(value); 136 } 137 } 138 resources.push(subresource); 139 } 140 }); 141 142 resources.sort(function (a, b) { return a.name < b.name ? -1 : 1; }); 143 144 if (resources.length) { 145 146 querystring = []; 147 AWS.util.arrayEach(resources, function (res) { 148 if (res.value === undefined) { 149 querystring.push(res.name); 150 } else { 151 querystring.push(res.name + '=' + res.value); 152 } 153 }); 154 155 resource += '?' + querystring.join('&'); 156 } 157 158 } 159 160 return resource; 161 162 }, 163 164 sign: function sign(secret, string) { 165 return AWS.util.crypto.hmac(secret, string, 'base64', 'sha1'); 166 } 167 }); 168 169 module.exports = AWS.Signers.S3;