fs: report correct path when EEXIST
[platform/upstream/nodejs.git] / deps / npm / node_modules / request / node_modules / aws-sign2 / index.js
1
2 /*!
3  * knox - auth
4  * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
5  * MIT Licensed
6  */
7
8 /**
9  * Module dependencies.
10  */
11
12 var crypto = require('crypto')
13   , parse = require('url').parse
14   ;
15
16 /**
17  * Valid keys.
18  */
19
20 var keys = 
21   [ 'acl'
22   , 'location'
23   , 'logging'
24   , 'notification'
25   , 'partNumber'
26   , 'policy'
27   , 'requestPayment'
28   , 'torrent'
29   , 'uploadId'
30   , 'uploads'
31   , 'versionId'
32   , 'versioning'
33   , 'versions'
34   , 'website'
35   ]
36
37 /**
38  * Return an "Authorization" header value with the given `options`
39  * in the form of "AWS <key>:<signature>"
40  *
41  * @param {Object} options
42  * @return {String}
43  * @api private
44  */
45
46 function authorization (options) {
47   return 'AWS ' + options.key + ':' + sign(options)
48 }
49
50 module.exports = authorization
51 module.exports.authorization = authorization
52
53 /**
54  * Simple HMAC-SHA1 Wrapper
55  *
56  * @param {Object} options
57  * @return {String}
58  * @api private
59  */ 
60
61 function hmacSha1 (options) {
62   return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64')
63 }
64
65 module.exports.hmacSha1 = hmacSha1
66
67 /**
68  * Create a base64 sha1 HMAC for `options`. 
69  * 
70  * @param {Object} options
71  * @return {String}
72  * @api private
73  */
74
75 function sign (options) {
76   options.message = stringToSign(options)
77   return hmacSha1(options)
78 }
79 module.exports.sign = sign
80
81 /**
82  * Create a base64 sha1 HMAC for `options`. 
83  *
84  * Specifically to be used with S3 presigned URLs
85  * 
86  * @param {Object} options
87  * @return {String}
88  * @api private
89  */
90
91 function signQuery (options) {
92   options.message = queryStringToSign(options)
93   return hmacSha1(options)
94 }
95 module.exports.signQuery= signQuery
96
97 /**
98  * Return a string for sign() with the given `options`.
99  *
100  * Spec:
101  * 
102  *    <verb>\n
103  *    <md5>\n
104  *    <content-type>\n
105  *    <date>\n
106  *    [headers\n]
107  *    <resource>
108  *
109  * @param {Object} options
110  * @return {String}
111  * @api private
112  */
113
114 function stringToSign (options) {
115   var headers = options.amazonHeaders || ''
116   if (headers) headers += '\n'
117   var r = 
118     [ options.verb
119     , options.md5
120     , options.contentType
121     , options.date ? options.date.toUTCString() : ''
122     , headers + options.resource
123     ]
124   return r.join('\n')
125 }
126 module.exports.queryStringToSign = stringToSign
127
128 /**
129  * Return a string for sign() with the given `options`, but is meant exclusively
130  * for S3 presigned URLs
131  *
132  * Spec:
133  * 
134  *    <date>\n
135  *    <resource>
136  *
137  * @param {Object} options
138  * @return {String}
139  * @api private
140  */
141
142 function queryStringToSign (options){
143   return 'GET\n\n\n' + options.date + '\n' + options.resource
144 }
145 module.exports.queryStringToSign = queryStringToSign
146
147 /**
148  * Perform the following:
149  *
150  *  - ignore non-amazon headers
151  *  - lowercase fields
152  *  - sort lexicographically
153  *  - trim whitespace between ":"
154  *  - join with newline
155  *
156  * @param {Object} headers
157  * @return {String}
158  * @api private
159  */
160
161 function canonicalizeHeaders (headers) {
162   var buf = []
163     , fields = Object.keys(headers)
164     ;
165   for (var i = 0, len = fields.length; i < len; ++i) {
166     var field = fields[i]
167       , val = headers[field]
168       , field = field.toLowerCase()
169       ;
170     if (0 !== field.indexOf('x-amz')) continue
171     buf.push(field + ':' + val)
172   }
173   return buf.sort().join('\n')
174 }
175 module.exports.canonicalizeHeaders = canonicalizeHeaders
176
177 /**
178  * Perform the following:
179  *
180  *  - ignore non sub-resources
181  *  - sort lexicographically
182  *
183  * @param {String} resource
184  * @return {String}
185  * @api private
186  */
187
188 function canonicalizeResource (resource) {
189   var url = parse(resource, true)
190     , path = url.pathname
191     , buf = []
192     ;
193
194   Object.keys(url.query).forEach(function(key){
195     if (!~keys.indexOf(key)) return
196     var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key])
197     buf.push(key + val)
198   })
199
200   return path + (buf.length ? '?' + buf.sort().join('&') : '')
201 }
202 module.exports.canonicalizeResource = canonicalizeResource