"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/aws4/aws4.js" (7 Feb 2017, 10759 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 var aws4 = exports,
    2     url = require('url'),
    3     querystring = require('querystring'),
    4     crypto = require('crypto'),
    5     lru = require('./lru'),
    6     credentialsCache = lru(1000)
    7 
    8 // http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html
    9 
   10 function hmac(key, string, encoding) {
   11   return crypto.createHmac('sha256', key).update(string, 'utf8').digest(encoding)
   12 }
   13 
   14 function hash(string, encoding) {
   15   return crypto.createHash('sha256').update(string, 'utf8').digest(encoding)
   16 }
   17 
   18 // This function assumes the string has already been percent encoded
   19 function encodeRfc3986(urlEncodedString) {
   20   return urlEncodedString.replace(/[!'()*]/g, function(c) {
   21     return '%' + c.charCodeAt(0).toString(16).toUpperCase()
   22   })
   23 }
   24 
   25 // request: { path | body, [host], [method], [headers], [service], [region] }
   26 // credentials: { accessKeyId, secretAccessKey, [sessionToken] }
   27 function RequestSigner(request, credentials) {
   28 
   29   if (typeof request === 'string') request = url.parse(request)
   30 
   31   var headers = request.headers = (request.headers || {}),
   32       hostParts = this.matchHost(request.hostname || request.host || headers.Host || headers.host)
   33 
   34   this.request = request
   35   this.credentials = credentials || this.defaultCredentials()
   36 
   37   this.service = request.service || hostParts[0] || ''
   38   this.region = request.region || hostParts[1] || 'us-east-1'
   39 
   40   // SES uses a different domain from the service name
   41   if (this.service === 'email') this.service = 'ses'
   42 
   43   if (!request.method && request.body)
   44     request.method = 'POST'
   45 
   46   if (!headers.Host && !headers.host) {
   47     headers.Host = request.hostname || request.host || this.createHost()
   48 
   49     // If a port is specified explicitly, use it as is
   50     if (request.port)
   51       headers.Host += ':' + request.port
   52   }
   53   if (!request.hostname && !request.host)
   54     request.hostname = headers.Host || headers.host
   55 
   56   this.isCodeCommitGit = this.service === 'codecommit' && request.method === 'GIT'
   57 }
   58 
   59 RequestSigner.prototype.matchHost = function(host) {
   60   var match = (host || '').match(/([^\.]+)\.(?:([^\.]*)\.)?amazonaws\.com$/)
   61   var hostParts = (match || []).slice(1, 3)
   62 
   63   // ES's hostParts are sometimes the other way round, if the value that is expected
   64   // to be region equals ‘es’ switch them back
   65   // e.g. search-cluster-name-aaaa00aaaa0aaa0aaaaaaa0aaa.us-east-1.es.amazonaws.com
   66   if (hostParts[1] === 'es')
   67     hostParts = hostParts.reverse()
   68 
   69   return hostParts
   70 }
   71 
   72 // http://docs.aws.amazon.com/general/latest/gr/rande.html
   73 RequestSigner.prototype.isSingleRegion = function() {
   74   // Special case for S3 and SimpleDB in us-east-1
   75   if (['s3', 'sdb'].indexOf(this.service) >= 0 && this.region === 'us-east-1') return true
   76 
   77   return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts']
   78     .indexOf(this.service) >= 0
   79 }
   80 
   81 RequestSigner.prototype.createHost = function() {
   82   var region = this.isSingleRegion() ? '' :
   83         (this.service === 's3' && this.region !== 'us-east-1' ? '-' : '.') + this.region,
   84       service = this.service === 'ses' ? 'email' : this.service
   85   return service + region + '.amazonaws.com'
   86 }
   87 
   88 RequestSigner.prototype.prepareRequest = function() {
   89   this.parsePath()
   90 
   91   var request = this.request, headers = request.headers, query
   92 
   93   if (request.signQuery) {
   94 
   95     this.parsedPath.query = query = this.parsedPath.query || {}
   96 
   97     if (this.credentials.sessionToken)
   98       query['X-Amz-Security-Token'] = this.credentials.sessionToken
   99 
  100     if (this.service === 's3' && !query['X-Amz-Expires'])
  101       query['X-Amz-Expires'] = 86400
  102 
  103     if (query['X-Amz-Date'])
  104       this.datetime = query['X-Amz-Date']
  105     else
  106       query['X-Amz-Date'] = this.getDateTime()
  107 
  108     query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'
  109     query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString()
  110     query['X-Amz-SignedHeaders'] = this.signedHeaders()
  111 
  112   } else {
  113 
  114     if (!request.doNotModifyHeaders && !this.isCodeCommitGit) {
  115       if (request.body && !headers['Content-Type'] && !headers['content-type'])
  116         headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'
  117 
  118       if (request.body && !headers['Content-Length'] && !headers['content-length'])
  119         headers['Content-Length'] = Buffer.byteLength(request.body)
  120 
  121       if (this.credentials.sessionToken && !headers['X-Amz-Security-Token'] && !headers['x-amz-security-token'])
  122         headers['X-Amz-Security-Token'] = this.credentials.sessionToken
  123 
  124       if (this.service === 's3' && !headers['X-Amz-Content-Sha256'] && !headers['x-amz-content-sha256'])
  125         headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex')
  126 
  127       if (headers['X-Amz-Date'] || headers['x-amz-date'])
  128         this.datetime = headers['X-Amz-Date'] || headers['x-amz-date']
  129       else
  130         headers['X-Amz-Date'] = this.getDateTime()
  131     }
  132 
  133     delete headers.Authorization
  134     delete headers.authorization
  135   }
  136 }
  137 
  138 RequestSigner.prototype.sign = function() {
  139   if (!this.parsedPath) this.prepareRequest()
  140 
  141   if (this.request.signQuery) {
  142     this.parsedPath.query['X-Amz-Signature'] = this.signature()
  143   } else {
  144     this.request.headers.Authorization = this.authHeader()
  145   }
  146 
  147   this.request.path = this.formatPath()
  148 
  149   return this.request
  150 }
  151 
  152 RequestSigner.prototype.getDateTime = function() {
  153   if (!this.datetime) {
  154     var headers = this.request.headers,
  155       date = new Date(headers.Date || headers.date || new Date)
  156 
  157     this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, '')
  158 
  159     // Remove the trailing 'Z' on the timestamp string for CodeCommit git access
  160     if (this.isCodeCommitGit) this.datetime = this.datetime.slice(0, -1)
  161   }
  162   return this.datetime
  163 }
  164 
  165 RequestSigner.prototype.getDate = function() {
  166   return this.getDateTime().substr(0, 8)
  167 }
  168 
  169 RequestSigner.prototype.authHeader = function() {
  170   return [
  171     'AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(),
  172     'SignedHeaders=' + this.signedHeaders(),
  173     'Signature=' + this.signature(),
  174   ].join(', ')
  175 }
  176 
  177 RequestSigner.prototype.signature = function() {
  178   var date = this.getDate(),
  179       cacheKey = [this.credentials.secretAccessKey, date, this.region, this.service].join(),
  180       kDate, kRegion, kService, kCredentials = credentialsCache.get(cacheKey)
  181   if (!kCredentials) {
  182     kDate = hmac('AWS4' + this.credentials.secretAccessKey, date)
  183     kRegion = hmac(kDate, this.region)
  184     kService = hmac(kRegion, this.service)
  185     kCredentials = hmac(kService, 'aws4_request')
  186     credentialsCache.set(cacheKey, kCredentials)
  187   }
  188   return hmac(kCredentials, this.stringToSign(), 'hex')
  189 }
  190 
  191 RequestSigner.prototype.stringToSign = function() {
  192   return [
  193     'AWS4-HMAC-SHA256',
  194     this.getDateTime(),
  195     this.credentialString(),
  196     hash(this.canonicalString(), 'hex'),
  197   ].join('\n')
  198 }
  199 
  200 RequestSigner.prototype.canonicalString = function() {
  201   if (!this.parsedPath) this.prepareRequest()
  202 
  203   var pathStr = this.parsedPath.path,
  204       query = this.parsedPath.query,
  205       headers = this.request.headers,
  206       queryStr = '',
  207       normalizePath = this.service !== 's3',
  208       decodePath = this.service === 's3' || this.request.doNotEncodePath,
  209       decodeSlashesInPath = this.service === 's3',
  210       firstValOnly = this.service === 's3',
  211       bodyHash
  212 
  213   if (this.service === 's3' && this.request.signQuery) {
  214     bodyHash = 'UNSIGNED-PAYLOAD'
  215   } else if (this.isCodeCommitGit) {
  216     bodyHash = ''
  217   } else {
  218     bodyHash = headers['X-Amz-Content-Sha256'] || headers['x-amz-content-sha256'] ||
  219       hash(this.request.body || '', 'hex')
  220   }
  221 
  222   if (query) {
  223     queryStr = encodeRfc3986(querystring.stringify(Object.keys(query).sort().reduce(function(obj, key) {
  224       if (!key) return obj
  225       obj[key] = !Array.isArray(query[key]) ? query[key] :
  226         (firstValOnly ? query[key][0] : query[key].slice().sort())
  227       return obj
  228     }, {})))
  229   }
  230   if (pathStr !== '/') {
  231     if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/')
  232     pathStr = pathStr.split('/').reduce(function(path, piece) {
  233       if (normalizePath && piece === '..') {
  234         path.pop()
  235       } else if (!normalizePath || piece !== '.') {
  236         if (decodePath) piece = querystring.unescape(piece)
  237         path.push(encodeRfc3986(querystring.escape(piece)))
  238       }
  239       return path
  240     }, []).join('/')
  241     if (pathStr[0] !== '/') pathStr = '/' + pathStr
  242     if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/')
  243   }
  244 
  245   return [
  246     this.request.method || 'GET',
  247     pathStr,
  248     queryStr,
  249     this.canonicalHeaders() + '\n',
  250     this.signedHeaders(),
  251     bodyHash,
  252   ].join('\n')
  253 }
  254 
  255 RequestSigner.prototype.canonicalHeaders = function() {
  256   var headers = this.request.headers
  257   function trimAll(header) {
  258     return header.toString().trim().replace(/\s+/g, ' ')
  259   }
  260   return Object.keys(headers)
  261     .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1 })
  262     .map(function(key) { return key.toLowerCase() + ':' + trimAll(headers[key]) })
  263     .join('\n')
  264 }
  265 
  266 RequestSigner.prototype.signedHeaders = function() {
  267   return Object.keys(this.request.headers)
  268     .map(function(key) { return key.toLowerCase() })
  269     .sort()
  270     .join(';')
  271 }
  272 
  273 RequestSigner.prototype.credentialString = function() {
  274   return [
  275     this.getDate(),
  276     this.region,
  277     this.service,
  278     'aws4_request',
  279   ].join('/')
  280 }
  281 
  282 RequestSigner.prototype.defaultCredentials = function() {
  283   var env = process.env
  284   return {
  285     accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY,
  286     secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY,
  287     sessionToken: env.AWS_SESSION_TOKEN,
  288   }
  289 }
  290 
  291 RequestSigner.prototype.parsePath = function() {
  292   var path = this.request.path || '/',
  293       queryIx = path.indexOf('?'),
  294       query = null
  295 
  296   if (queryIx >= 0) {
  297     query = querystring.parse(path.slice(queryIx + 1))
  298     path = path.slice(0, queryIx)
  299   }
  300 
  301   // S3 doesn't always encode characters > 127 correctly and
  302   // all services don't encode characters > 255 correctly
  303   // So if there are non-reserved chars (and it's not already all % encoded), just encode them all
  304   if (/[^0-9A-Za-z!'()*\-._~%/]/.test(path)) {
  305     path = path.split('/').map(function(piece) {
  306       return querystring.escape(querystring.unescape(piece))
  307     }).join('/')
  308   }
  309 
  310   this.parsedPath = {
  311     path: path,
  312     query: query,
  313   }
  314 }
  315 
  316 RequestSigner.prototype.formatPath = function() {
  317   var path = this.parsedPath.path,
  318       query = this.parsedPath.query
  319 
  320   if (!query) return path
  321 
  322   // Services don't support empty query string keys
  323   if (query[''] != null) delete query['']
  324 
  325   return path + '?' + encodeRfc3986(querystring.stringify(query))
  326 }
  327 
  328 aws4.RequestSigner = RequestSigner
  329 
  330 aws4.sign = function(request, credentials) {
  331   return new RequestSigner(request, credentials).sign()
  332 }