mirror of
https://github.com/amark/gun.git
synced 2025-06-09 07:36:44 +00:00
161 lines
5.1 KiB
JavaScript
161 lines
5.1 KiB
JavaScript
var AWS = require('../core');
|
|
var inherit = AWS.util.inherit;
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
var cachedSecret = {};
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
AWS.Signers.V4 = inherit(AWS.Signers.RequestSigner, {
|
|
constructor: function V4(request, serviceName) {
|
|
AWS.Signers.RequestSigner.call(this, request);
|
|
this.serviceName = serviceName;
|
|
},
|
|
|
|
addAuthorization: function addAuthorization(credentials, date) {
|
|
var datetime = AWS.util.date.iso8601(date).replace(/[:\-]|\.\d{3}/g, '');
|
|
this.addHeaders(credentials, datetime);
|
|
this.updateBody(credentials);
|
|
this.request.headers['Authorization'] =
|
|
this.authorization(credentials, datetime);
|
|
},
|
|
|
|
addHeaders: function addHeaders(credentials, datetime) {
|
|
this.request.headers['X-Amz-Date'] = datetime;
|
|
if (credentials.sessionToken) {
|
|
this.request.headers['x-amz-security-token'] = credentials.sessionToken;
|
|
}
|
|
},
|
|
|
|
updateBody: function updateBody(credentials) {
|
|
if (this.request.params) {
|
|
this.request.params.AWSAccessKeyId = credentials.accessKeyId;
|
|
|
|
if (credentials.sessionToken) {
|
|
this.request.params.SecurityToken = credentials.sessionToken;
|
|
}
|
|
|
|
this.request.body = AWS.util.queryParamsToString(this.request.params);
|
|
this.request.headers['Content-Length'] = this.request.body.length;
|
|
}
|
|
},
|
|
|
|
authorization: function authorization(credentials, datetime) {
|
|
var parts = [];
|
|
var credString = this.credentialString(datetime);
|
|
parts.push('AWS4-HMAC-SHA256 Credential=' +
|
|
credentials.accessKeyId + '/' + credString);
|
|
parts.push('SignedHeaders=' + this.signedHeaders());
|
|
parts.push('Signature=' + this.signature(credentials, datetime));
|
|
return parts.join(', ');
|
|
},
|
|
|
|
signature: function signature(credentials, datetime) {
|
|
var cache = cachedSecret[this.serviceName];
|
|
var date = datetime.substr(0, 8);
|
|
if (!cache ||
|
|
cache.akid !== credentials.accessKeyId ||
|
|
cache.region !== this.request.region ||
|
|
cache.date !== date) {
|
|
var kSecret = credentials.secretAccessKey;
|
|
var kDate = AWS.util.crypto.hmac('AWS4' + kSecret, date, 'buffer');
|
|
var kRegion = AWS.util.crypto.hmac(kDate, this.request.region, 'buffer');
|
|
var kService = AWS.util.crypto.hmac(kRegion, this.serviceName, 'buffer');
|
|
var kCredentials = AWS.util.crypto.hmac(kService, 'aws4_request', 'buffer');
|
|
cachedSecret[this.serviceName] = {
|
|
region: this.request.region, date: date,
|
|
key: kCredentials, akid: credentials.accessKeyId
|
|
};
|
|
}
|
|
|
|
var key = cachedSecret[this.serviceName].key;
|
|
return AWS.util.crypto.hmac(key, this.stringToSign(datetime), 'hex');
|
|
},
|
|
|
|
stringToSign: function stringToSign(datetime) {
|
|
var parts = [];
|
|
parts.push('AWS4-HMAC-SHA256');
|
|
parts.push(datetime);
|
|
parts.push(this.credentialString(datetime));
|
|
parts.push(this.hexEncodedHash(this.canonicalString()));
|
|
return parts.join('\n');
|
|
},
|
|
|
|
canonicalString: function canonicalString() {
|
|
var parts = [];
|
|
parts.push(this.request.method);
|
|
parts.push(this.request.pathname());
|
|
parts.push(this.request.search());
|
|
parts.push(this.canonicalHeaders() + '\n');
|
|
parts.push(this.signedHeaders());
|
|
parts.push(this.hexEncodedBodyHash());
|
|
return parts.join('\n');
|
|
},
|
|
|
|
canonicalHeaders: function canonicalHeaders() {
|
|
var headers = [];
|
|
AWS.util.each.call(this, this.request.headers, function (key, item) {
|
|
headers.push([key, item]);
|
|
});
|
|
headers.sort(function (a, b) {
|
|
return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : 1;
|
|
});
|
|
var parts = [];
|
|
AWS.util.arrayEach.call(this, headers, function (item) {
|
|
var key = item[0].toLowerCase();
|
|
if (this.isSignableHeader(key)) {
|
|
parts.push(key + ':' +
|
|
this.canonicalHeaderValues(item[1].toString()));
|
|
}
|
|
});
|
|
return parts.join('\n');
|
|
},
|
|
|
|
canonicalHeaderValues: function canonicalHeaderValues(values) {
|
|
return values.replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '');
|
|
},
|
|
|
|
signedHeaders: function signedHeaders() {
|
|
var keys = [];
|
|
AWS.util.each.call(this, this.request.headers, function (key) {
|
|
key = key.toLowerCase();
|
|
if (this.isSignableHeader(key)) keys.push(key);
|
|
});
|
|
return keys.sort().join(';');
|
|
},
|
|
|
|
credentialString: function credentialString(datetime) {
|
|
var parts = [];
|
|
parts.push(datetime.substr(0, 8));
|
|
parts.push(this.request.region);
|
|
parts.push(this.serviceName);
|
|
parts.push('aws4_request');
|
|
return parts.join('/');
|
|
},
|
|
|
|
hexEncodedHash: function hash(string) {
|
|
return AWS.util.crypto.sha256(string, 'hex');
|
|
},
|
|
|
|
hexEncodedBodyHash: function hexEncodedBodyHash() {
|
|
if (this.request.headers['X-Amz-Content-Sha256']) {
|
|
return this.request.headers['X-Amz-Content-Sha256'];
|
|
} else {
|
|
return this.hexEncodedHash(this.request.body || '');
|
|
}
|
|
},
|
|
|
|
unsignableHeaders: ['authorization', 'content-type', 'user-agent',
|
|
'x-amz-user-agent', 'x-amz-content-sha256'],
|
|
|
|
isSignableHeader: function isSignableHeader(key) {
|
|
return this.unsignableHeaders.indexOf(key) < 0;
|
|
}
|
|
|
|
});
|
|
|
|
module.exports = AWS.Signers.V4;
|