twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

index.js (4416B)


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