-
Notifications
You must be signed in to change notification settings - Fork 1
/
aws2.js
121 lines (95 loc) · 3.89 KB
/
aws2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
var aws2 = exports,
url = require('url'),
crypto = require('crypto'),
querystring = require('querystring')
// http://docs.amazonwebservices.com/general/latest/gr/signature-version-2.html
// request: { path | body, [host], [method], [headers], [service], [region] }
// credentials: { accessKeyId, secretAccessKey, [sessionToken] }
function RequestSigner(request, credentials) {
if (typeof request === 'string') request = url.parse(request)
var headers = request.headers || {},
hostParts = this.matchHost(request.hostname || request.host || headers.Host)
this.request = request
this.credentials = credentials || this.defaultCredentials()
this.service = request.service || hostParts[0] || ''
this.region = request.region || hostParts[1] || 'us-east-1'
}
RequestSigner.prototype.matchHost = function(host) {
var match = (host || '').match(/^([^\.]+)\.?([^\.]*)\.amazonaws\.com$/)
return (match || []).slice(1, 3)
}
// http://docs.aws.amazon.com/general/latest/gr/rande.html
RequestSigner.prototype.isSingleRegion = function() {
// Special case for SimpleDB in us-east-1
if (this.service === 'sdb' && this.region === 'us-east-1') return true
return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts']
.indexOf(this.service) >= 0
}
RequestSigner.prototype.createHost = function() {
var region = this.isSingleRegion() ? '' : '.' + this.region
return this.service + region + '.amazonaws.com'
}
RequestSigner.prototype.sign = function() {
var request = this.request,
headers = request.headers = (request.headers || {}),
date = new Date(headers.Date || new Date),
pathParts = this.pathParts = (request.path || '/').split('?', 2),
query = request.body || pathParts[1],
params = this.params = querystring.parse(query)
if (!request.method && request.body)
request.method = 'POST'
if (!headers.Host && !headers.host)
headers.Host = request.hostname || request.host || this.createHost()
if (!request.hostname && !request.host)
request.hostname = headers.Host || headers.host
if (request.body && !headers['Content-Type'] && !headers['content-type'])
headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'
if (this.credentials.sessionToken) {
headers['X-Amz-Security-Token'] = this.credentials.sessionToken
params.SecurityToken = this.credentials.sessionToken
}
params.Timestamp = date.toISOString()
params.SignatureVersion = '2'
params.SignatureMethod = 'HmacSHA256'
params.AWSAccessKeyId = this.credentials.accessKeyId
if (params.Signature) delete params.Signature
params.Signature = this.signature()
query = querystring.stringify(params)
if (request.body) {
request.body = query
headers['Content-Length'] = Buffer.byteLength(request.body)
} else {
request.path = pathParts[0] + '?' + query
}
return request
}
RequestSigner.prototype.signature = function() {
return crypto.createHmac('sha256', this.credentials.secretAccessKey)
.update(this.stringToSign(), 'utf8').digest('base64')
}
RequestSigner.prototype.stringToSign = function() {
return [
this.request.method || 'GET',
(this.request.hostname || this.request.host).toLowerCase(),
this.pathParts[0] || '/',
this.canonicalParams()
].join('\n')
}
RequestSigner.prototype.canonicalParams = function() {
var params = this.params
return Object.keys(params).sort().map(function(key) {
return querystring.escape(key) + '=' + querystring.escape(params[key])
}).join('&')
}
RequestSigner.prototype.defaultCredentials = function() {
var env = process.env
return {
accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY,
sessionToken: env.AWS_SESSION_TOKEN
}
}
aws2.RequestSigner = RequestSigner
aws2.sign = function(request, credentials) {
return new RequestSigner(request, credentials).sign()
}