├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── aws4.js ├── browser ├── README.md ├── index.html ├── index.js ├── package-lock.json └── package.json ├── example.js ├── lru.js ├── package-lock.json ├── package.json └── test ├── aws-sig-v4-test-suite ├── get-header-key-duplicate │ ├── get-header-key-duplicate.authz │ ├── get-header-key-duplicate.creq │ ├── get-header-key-duplicate.req │ ├── get-header-key-duplicate.sreq │ └── get-header-key-duplicate.sts ├── get-header-value-multiline │ ├── get-header-value-multiline.authz │ ├── get-header-value-multiline.creq │ ├── get-header-value-multiline.req │ ├── get-header-value-multiline.sreq │ └── get-header-value-multiline.sts ├── get-header-value-order │ ├── get-header-value-order.authz │ ├── get-header-value-order.creq │ ├── get-header-value-order.req │ ├── get-header-value-order.sreq │ └── get-header-value-order.sts ├── get-header-value-trim │ ├── get-header-value-trim.authz │ ├── get-header-value-trim.creq │ ├── get-header-value-trim.req │ ├── get-header-value-trim.sreq │ └── get-header-value-trim.sts ├── get-unreserved │ ├── get-unreserved.authz │ ├── get-unreserved.creq │ ├── get-unreserved.req │ ├── get-unreserved.sreq │ └── get-unreserved.sts ├── get-utf8 │ ├── get-utf8.authz │ ├── get-utf8.creq │ ├── get-utf8.req │ ├── get-utf8.sreq │ └── get-utf8.sts ├── get-vanilla-empty-query-key │ ├── get-vanilla-empty-query-key.authz │ ├── get-vanilla-empty-query-key.creq │ ├── get-vanilla-empty-query-key.req │ ├── get-vanilla-empty-query-key.sreq │ └── get-vanilla-empty-query-key.sts ├── get-vanilla-query-order-key-case │ ├── get-vanilla-query-order-key-case.authz │ ├── get-vanilla-query-order-key-case.creq │ ├── get-vanilla-query-order-key-case.req │ ├── get-vanilla-query-order-key-case.sreq │ └── get-vanilla-query-order-key-case.sts ├── get-vanilla-query-order-key │ ├── get-vanilla-query-order-key.authz │ ├── get-vanilla-query-order-key.creq │ ├── get-vanilla-query-order-key.req │ ├── get-vanilla-query-order-key.sreq │ └── get-vanilla-query-order-key.sts ├── get-vanilla-query-order-value │ ├── get-vanilla-query-order-value.authz │ ├── get-vanilla-query-order-value.creq │ ├── get-vanilla-query-order-value.req │ ├── get-vanilla-query-order-value.sreq │ └── get-vanilla-query-order-value.sts ├── get-vanilla-query-unreserved │ ├── get-vanilla-query-unreserved.authz │ ├── get-vanilla-query-unreserved.creq │ ├── get-vanilla-query-unreserved.req │ ├── get-vanilla-query-unreserved.sreq │ └── get-vanilla-query-unreserved.sts ├── get-vanilla-query │ ├── get-vanilla-query.authz │ ├── get-vanilla-query.creq │ ├── get-vanilla-query.req │ ├── get-vanilla-query.sreq │ └── get-vanilla-query.sts ├── get-vanilla-utf8-query │ ├── get-vanilla-utf8-query.authz │ ├── get-vanilla-utf8-query.creq │ ├── get-vanilla-utf8-query.req │ ├── get-vanilla-utf8-query.sreq │ └── get-vanilla-utf8-query.sts ├── get-vanilla │ ├── get-vanilla.authz │ ├── get-vanilla.creq │ ├── get-vanilla.req │ ├── get-vanilla.sreq │ └── get-vanilla.sts ├── normalize-path │ ├── get-relative-relative │ │ ├── get-relative-relative.authz │ │ ├── get-relative-relative.creq │ │ ├── get-relative-relative.req │ │ ├── get-relative-relative.sreq │ │ └── get-relative-relative.sts │ ├── get-relative │ │ ├── get-relative.authz │ │ ├── get-relative.creq │ │ ├── get-relative.req │ │ ├── get-relative.sreq │ │ └── get-relative.sts │ ├── get-slash-dot-slash │ │ ├── get-slash-dot-slash.authz │ │ ├── get-slash-dot-slash.creq │ │ ├── get-slash-dot-slash.req │ │ ├── get-slash-dot-slash.sreq │ │ └── get-slash-dot-slash.sts │ ├── get-slash-pointless-dot │ │ ├── get-slash-pointless-dot.authz │ │ ├── get-slash-pointless-dot.creq │ │ ├── get-slash-pointless-dot.req │ │ ├── get-slash-pointless-dot.sreq │ │ └── get-slash-pointless-dot.sts │ ├── get-slash │ │ ├── get-slash.authz │ │ ├── get-slash.creq │ │ ├── get-slash.req │ │ ├── get-slash.sreq │ │ └── get-slash.sts │ ├── get-slashes │ │ ├── get-slashes.authz │ │ ├── get-slashes.creq │ │ ├── get-slashes.req │ │ ├── get-slashes.sreq │ │ └── get-slashes.sts │ ├── get-space │ │ ├── get-space.authz │ │ ├── get-space.creq │ │ ├── get-space.req │ │ ├── get-space.sreq │ │ └── get-space.sts │ └── normalize-path.txt ├── post-header-key-case │ ├── post-header-key-case.authz │ ├── post-header-key-case.creq │ ├── post-header-key-case.req │ ├── post-header-key-case.sreq │ └── post-header-key-case.sts ├── post-header-key-sort │ ├── post-header-key-sort.authz │ ├── post-header-key-sort.creq │ ├── post-header-key-sort.req │ ├── post-header-key-sort.sreq │ └── post-header-key-sort.sts ├── post-header-value-case │ ├── post-header-value-case.authz │ ├── post-header-value-case.creq │ ├── post-header-value-case.req │ ├── post-header-value-case.sreq │ └── post-header-value-case.sts ├── post-sts-token │ ├── post-sts-header-after │ │ ├── post-sts-header-after.authz │ │ ├── post-sts-header-after.creq │ │ ├── post-sts-header-after.req │ │ ├── post-sts-header-after.sreq │ │ └── post-sts-header-after.sts │ ├── post-sts-header-before │ │ ├── post-sts-header-before.authz │ │ ├── post-sts-header-before.creq │ │ ├── post-sts-header-before.req │ │ ├── post-sts-header-before.sreq │ │ └── post-sts-header-before.sts │ └── readme.txt ├── post-vanilla-empty-query-value │ ├── post-vanilla-empty-query-value.authz │ ├── post-vanilla-empty-query-value.creq │ ├── post-vanilla-empty-query-value.req │ ├── post-vanilla-empty-query-value.sreq │ └── post-vanilla-empty-query-value.sts ├── post-vanilla-query │ ├── post-vanilla-query.authz │ ├── post-vanilla-query.creq │ ├── post-vanilla-query.req │ ├── post-vanilla-query.sreq │ └── post-vanilla-query.sts ├── post-vanilla │ ├── post-vanilla.authz │ ├── post-vanilla.creq │ ├── post-vanilla.req │ ├── post-vanilla.sreq │ └── post-vanilla.sts ├── post-x-www-form-urlencoded-parameters │ ├── post-x-www-form-urlencoded-parameters.authz │ ├── post-x-www-form-urlencoded-parameters.creq │ ├── post-x-www-form-urlencoded-parameters.req │ ├── post-x-www-form-urlencoded-parameters.sreq │ └── post-x-www-form-urlencoded-parameters.sts └── post-x-www-form-urlencoded │ ├── post-x-www-form-urlencoded.authz │ ├── post-x-www-form-urlencoded.creq │ ├── post-x-www-form-urlencoded.req │ ├── post-x-www-form-urlencoded.sreq │ └── post-x-www-form-urlencoded.sts ├── fast.js └── slow.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.authz text eol=lf 2 | *.creq text eol=lf 3 | *.req text eol=lf 4 | *.sreq text eol=lf 5 | *.sts text eol=lf 6 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: [ push, pull_request ] 4 | 5 | defaults: 6 | run: 7 | shell: bash 8 | 9 | jobs: 10 | 11 | test: 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | node-version: [ 14.x, 16.x, 18.x, 20.x ] 16 | # TODO: Do we really need to test on windows and macOS? 17 | # We don't even touch the filesystem, let OS stuff 18 | # os: [ windows-latest, ubuntu-latest, macOS-latest ] 19 | os: [ ubuntu-latest ] 20 | 21 | steps: 22 | - name: Check out repo 23 | uses: actions/checkout@v3 24 | 25 | - name: Set up Node.js 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | 30 | - name: Env 31 | run: | 32 | echo "Event name: ${{ github.event_name }}" 33 | echo "Git ref: ${{ github.ref }}" 34 | echo "GH actor: ${{ github.actor }}" 35 | echo "SHA: ${{ github.sha }}" 36 | VER=`node --version`; echo "Node ver: $VER" 37 | VER=`npm --version`; echo "npm ver: $VER" 38 | 39 | - name: Install 40 | run: npm install 41 | 42 | - name: Test 43 | run: npm test 44 | env: 45 | CI: true 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage* 3 | browser/bundle.js 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Michael Hart (michael.hart.au@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | aws4 2 | ---- 3 | 4 | A small utility to sign [vanilla Node.js http(s)](https://nodejs.org/api/http.html) request options using Amazon's 5 | [AWS Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). 6 | 7 | If you want to sign and send AWS requests using [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), then check out [aws4fetch](https://github.com/mhart/aws4fetch) – otherwise you can also bundle this library for use [in older browsers](./browser). 8 | 9 | The only AWS service I know of that *doesn't* support v4 is 10 | [SimpleDB](https://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API.html) 11 | (it only supports [AWS Signature Version 2](https://github.com/mhart/aws2)). 12 | 13 | It also provides defaults for a number of core AWS headers and 14 | request parameters, making it very easy to query AWS services, or 15 | build out a fully-featured AWS library. 16 | 17 | Example 18 | ------- 19 | 20 | ```javascript 21 | var https = require('https') 22 | var aws4 = require('aws4') 23 | 24 | // to illustrate usage, we'll create a utility function to request and pipe to stdout 25 | function request(opts) { https.request(opts, function(res) { res.pipe(process.stdout) }).end(opts.body || '') } 26 | 27 | // aws4 will sign an options object as you'd pass to http.request, with an AWS service and region 28 | var opts = { host: 'my-bucket.s3.us-west-1.amazonaws.com', path: '/my-object', service: 's3', region: 'us-west-1' } 29 | 30 | // aws4.sign() will sign and modify these options, ready to pass to http.request 31 | aws4.sign(opts, { accessKeyId: '', secretAccessKey: '' }) 32 | 33 | // or it can get credentials from process.env.AWS_ACCESS_KEY_ID, etc 34 | aws4.sign(opts) 35 | 36 | // for most AWS services, aws4 can figure out the service and region if you pass a host 37 | opts = { host: 'my-bucket.s3.us-west-1.amazonaws.com', path: '/my-object' } 38 | 39 | // usually it will add/modify request headers, but you can also sign the query: 40 | opts = { host: 'my-bucket.s3.amazonaws.com', path: '/?X-Amz-Expires=12345', signQuery: true } 41 | 42 | // and for services with simple hosts, aws4 can infer the host from service and region: 43 | opts = { service: 'sqs', region: 'us-east-1', path: '/?Action=ListQueues' } 44 | 45 | // and if you're using us-east-1, it's the default: 46 | opts = { service: 'sqs', path: '/?Action=ListQueues' } 47 | 48 | aws4.sign(opts) 49 | console.log(opts) 50 | /* 51 | { 52 | host: 'sqs.us-east-1.amazonaws.com', 53 | path: '/?Action=ListQueues', 54 | headers: { 55 | Host: 'sqs.us-east-1.amazonaws.com', 56 | 'X-Amz-Date': '20121226T061030Z', 57 | Authorization: 'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/sqs/aws4_request, ...' 58 | } 59 | } 60 | */ 61 | 62 | // we can now use this to query AWS 63 | request(opts) 64 | /* 65 | 66 | 67 | ... 68 | */ 69 | 70 | // aws4 can infer the HTTP method if a body is passed in 71 | // method will be POST and Content-Type: 'application/x-www-form-urlencoded; charset=utf-8' 72 | request(aws4.sign({ service: 'iam', body: 'Action=ListGroups&Version=2010-05-08' })) 73 | /* 74 | 75 | ... 76 | */ 77 | 78 | // you can specify any custom option or header as per usual 79 | request(aws4.sign({ 80 | service: 'dynamodb', 81 | region: 'ap-southeast-2', 82 | method: 'POST', 83 | path: '/', 84 | headers: { 85 | 'Content-Type': 'application/x-amz-json-1.0', 86 | 'X-Amz-Target': 'DynamoDB_20120810.ListTables' 87 | }, 88 | body: '{}' 89 | })) 90 | /* 91 | {"TableNames":[]} 92 | ... 93 | */ 94 | 95 | // you can also specify extra headers to ignore during signing 96 | request(aws4.sign({ 97 | host: '07tjusf2h91cunochc.us-east-1.aoss.amazonaws.com', 98 | method: 'PUT', 99 | path: '/my-index', 100 | body: '{"mappings":{}}', 101 | headers: { 102 | 'Content-Type': 'application/json', 103 | 'X-Amz-Content-Sha256': 'UNSIGNED-PAYLOAD' 104 | }, 105 | extraHeadersToIgnore: { 106 | 'content-length': true 107 | } 108 | })) 109 | 110 | // and headers to include that would normally be ignored 111 | request(aws4.sign({ 112 | service: 'mycustomservice', 113 | path: '/whatever', 114 | headers: { 115 | 'Range': 'bytes=200-1000, 2000-6576, 19000-' 116 | }, 117 | extraHeadersToInclude: { 118 | 'range': true 119 | } 120 | })) 121 | 122 | 123 | // The raw RequestSigner can be used to generate CodeCommit Git passwords 124 | var signer = new aws4.RequestSigner({ 125 | service: 'codecommit', 126 | host: 'git-codecommit.us-east-1.amazonaws.com', 127 | method: 'GIT', 128 | path: '/v1/repos/MyAwesomeRepo', 129 | }) 130 | var password = signer.getDateTime() + 'Z' + signer.signature() 131 | 132 | // see example.js for examples with other services 133 | ``` 134 | 135 | API 136 | --- 137 | 138 | ### aws4.sign(requestOptions, [credentials]) 139 | 140 | Calculates and populates any necessary AWS headers and/or request 141 | options on `requestOptions`. Returns `requestOptions` as a convenience for chaining. 142 | 143 | `requestOptions` is an object holding the same options that the Node.js 144 | [http.request](https://nodejs.org/docs/latest/api/http.html#http_http_request_options_callback) 145 | function takes. 146 | 147 | The following properties of `requestOptions` are used in the signing or 148 | populated if they don't already exist: 149 | 150 | - `hostname` or `host` (will try to be determined from `service` and `region` if not given) 151 | - `method` (will use `'GET'` if not given or `'POST'` if there is a `body`) 152 | - `path` (will use `'/'` if not given) 153 | - `body` (will use `''` if not given) 154 | - `service` (will try to be calculated from `hostname` or `host` if not given) 155 | - `region` (will try to be calculated from `hostname` or `host` or use `'us-east-1'` if not given) 156 | - `signQuery` (to sign the query instead of adding an `Authorization` header, defaults to false) 157 | - `extraHeadersToIgnore` (an object with lowercase header keys to ignore when signing, eg `{ 'content-length': true }`) 158 | - `extraHeadersToInclude` (an object with lowercase header keys to include when signing, overriding any ignores) 159 | - `headers['Host']` (will use `hostname` or `host` or be calculated if not given) 160 | - `headers['Content-Type']` (will use `'application/x-www-form-urlencoded; charset=utf-8'` 161 | if not given and there is a `body`) 162 | - `headers['Date']` (used to calculate the signature date if given, otherwise `new Date` is used) 163 | 164 | Your AWS credentials (which can be found in your 165 | [AWS console](https://portal.aws.amazon.com/gp/aws/securityCredentials)) 166 | can be specified in one of two ways: 167 | 168 | - As the second argument, like this: 169 | 170 | ```javascript 171 | aws4.sign(requestOptions, { 172 | secretAccessKey: "", 173 | accessKeyId: "", 174 | sessionToken: "" 175 | }) 176 | ``` 177 | 178 | - From `process.env`, such as this: 179 | 180 | ``` 181 | export AWS_ACCESS_KEY_ID="" 182 | export AWS_SECRET_ACCESS_KEY="" 183 | export AWS_SESSION_TOKEN="" 184 | ``` 185 | 186 | (will also use `AWS_ACCESS_KEY` and `AWS_SECRET_KEY` if available) 187 | 188 | The `sessionToken` property and `AWS_SESSION_TOKEN` environment variable are optional for signing 189 | with [IAM STS temporary credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html). 190 | 191 | Installation 192 | ------------ 193 | 194 | With [npm](https://www.npmjs.com/) do: 195 | 196 | ``` 197 | npm install aws4 198 | ``` 199 | 200 | Can also be used [in the browser](./browser). 201 | 202 | Thanks 203 | ------ 204 | 205 | Thanks to [@jed](https://github.com/jed) for his 206 | [dynamo-client](https://github.com/jed/dynamo-client) lib where I first 207 | committed and subsequently extracted this code. 208 | 209 | Also thanks to the 210 | [official Node.js AWS SDK](https://github.com/aws/aws-sdk-js) for giving 211 | me a start on implementing the v4 signature. 212 | -------------------------------------------------------------------------------- /aws4.js: -------------------------------------------------------------------------------- 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 | function encodeRfc3986Full(str) { 26 | return encodeRfc3986(encodeURIComponent(str)) 27 | } 28 | 29 | // A bit of a combination of: 30 | // https://github.com/aws/aws-sdk-java-v2/blob/dc695de6ab49ad03934e1b02e7263abbd2354be0/core/auth/src/main/java/software/amazon/awssdk/auth/signer/internal/AbstractAws4Signer.java#L59 31 | // https://github.com/aws/aws-sdk-js/blob/18cb7e5b463b46239f9fdd4a65e2ff8c81831e8f/lib/signers/v4.js#L191-L199 32 | // https://github.com/mhart/aws4fetch/blob/b3aed16b6f17384cf36ea33bcba3c1e9f3bdfefd/src/main.js#L25-L34 33 | var HEADERS_TO_IGNORE = { 34 | 'authorization': true, 35 | 'connection': true, 36 | 'x-amzn-trace-id': true, 37 | 'user-agent': true, 38 | 'expect': true, 39 | 'presigned-expires': true, 40 | 'range': true, 41 | } 42 | 43 | // request: { path | body, [host], [method], [headers], [service], [region] } 44 | // credentials: { accessKeyId, secretAccessKey, [sessionToken] } 45 | function RequestSigner(request, credentials) { 46 | 47 | if (typeof request === 'string') request = url.parse(request) 48 | 49 | var headers = request.headers = Object.assign({}, (request.headers || {})), 50 | hostParts = (!this.service || !this.region) && this.matchHost(request.hostname || request.host || headers.Host || headers.host) 51 | 52 | this.request = request 53 | this.credentials = credentials || this.defaultCredentials() 54 | 55 | this.service = request.service || hostParts[0] || '' 56 | this.region = request.region || hostParts[1] || 'us-east-1' 57 | 58 | // SES uses a different domain from the service name 59 | if (this.service === 'email') this.service = 'ses' 60 | 61 | if (!request.method && request.body) 62 | request.method = 'POST' 63 | 64 | if (!headers.Host && !headers.host) { 65 | headers.Host = request.hostname || request.host || this.createHost() 66 | 67 | // If a port is specified explicitly, use it as is 68 | if (request.port) 69 | headers.Host += ':' + request.port 70 | } 71 | if (!request.hostname && !request.host) 72 | request.hostname = headers.Host || headers.host 73 | 74 | this.isCodeCommitGit = this.service === 'codecommit' && request.method === 'GIT' 75 | 76 | this.extraHeadersToIgnore = request.extraHeadersToIgnore || Object.create(null) 77 | this.extraHeadersToInclude = request.extraHeadersToInclude || Object.create(null) 78 | } 79 | 80 | RequestSigner.prototype.matchHost = function(host) { 81 | var match = (host || '').match(/([^\.]{1,63})\.(?:([^\.]{0,63})\.)?amazonaws\.com(\.cn)?$/) 82 | var hostParts = (match || []).slice(1, 3) 83 | 84 | // ES's hostParts are sometimes the other way round, if the value that is expected 85 | // to be region equals ‘es’ switch them back 86 | // e.g. search-cluster-name-aaaa00aaaa0aaa0aaaaaaa0aaa.us-east-1.es.amazonaws.com 87 | if (hostParts[1] === 'es' || hostParts[1] === 'aoss') 88 | hostParts = hostParts.reverse() 89 | 90 | if (hostParts[1] == 's3') { 91 | hostParts[0] = 's3' 92 | hostParts[1] = 'us-east-1' 93 | } else { 94 | for (var i = 0; i < 2; i++) { 95 | if (/^s3-/.test(hostParts[i])) { 96 | hostParts[1] = hostParts[i].slice(3) 97 | hostParts[0] = 's3' 98 | break 99 | } 100 | } 101 | } 102 | 103 | return hostParts 104 | } 105 | 106 | // http://docs.aws.amazon.com/general/latest/gr/rande.html 107 | RequestSigner.prototype.isSingleRegion = function() { 108 | // Special case for S3 and SimpleDB in us-east-1 109 | if (['s3', 'sdb'].indexOf(this.service) >= 0 && this.region === 'us-east-1') return true 110 | 111 | return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts'] 112 | .indexOf(this.service) >= 0 113 | } 114 | 115 | RequestSigner.prototype.createHost = function() { 116 | var region = this.isSingleRegion() ? '' : '.' + this.region, 117 | subdomain = this.service === 'ses' ? 'email' : this.service 118 | return subdomain + region + '.amazonaws.com' 119 | } 120 | 121 | RequestSigner.prototype.prepareRequest = function() { 122 | this.parsePath() 123 | 124 | var request = this.request, headers = request.headers, query 125 | 126 | if (request.signQuery) { 127 | 128 | this.parsedPath.query = query = this.parsedPath.query || {} 129 | 130 | if (this.credentials.sessionToken) 131 | query['X-Amz-Security-Token'] = this.credentials.sessionToken 132 | 133 | if (this.service === 's3' && !query['X-Amz-Expires']) 134 | query['X-Amz-Expires'] = 86400 135 | 136 | if (query['X-Amz-Date']) 137 | this.datetime = query['X-Amz-Date'] 138 | else 139 | query['X-Amz-Date'] = this.getDateTime() 140 | 141 | query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256' 142 | query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString() 143 | query['X-Amz-SignedHeaders'] = this.signedHeaders() 144 | 145 | } else { 146 | 147 | if (!request.doNotModifyHeaders && !this.isCodeCommitGit) { 148 | if (request.body && !headers['Content-Type'] && !headers['content-type']) 149 | headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8' 150 | 151 | if (request.body && !headers['Content-Length'] && !headers['content-length']) 152 | headers['Content-Length'] = Buffer.byteLength(request.body) 153 | 154 | if (this.credentials.sessionToken && !headers['X-Amz-Security-Token'] && !headers['x-amz-security-token']) 155 | headers['X-Amz-Security-Token'] = this.credentials.sessionToken 156 | 157 | if (this.service === 's3' && !headers['X-Amz-Content-Sha256'] && !headers['x-amz-content-sha256']) 158 | headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex') 159 | 160 | if (headers['X-Amz-Date'] || headers['x-amz-date']) 161 | this.datetime = headers['X-Amz-Date'] || headers['x-amz-date'] 162 | else 163 | headers['X-Amz-Date'] = this.getDateTime() 164 | } 165 | 166 | delete headers.Authorization 167 | delete headers.authorization 168 | } 169 | } 170 | 171 | RequestSigner.prototype.sign = function() { 172 | if (!this.parsedPath) this.prepareRequest() 173 | 174 | if (this.request.signQuery) { 175 | this.parsedPath.query['X-Amz-Signature'] = this.signature() 176 | } else { 177 | this.request.headers.Authorization = this.authHeader() 178 | } 179 | 180 | this.request.path = this.formatPath() 181 | 182 | return this.request 183 | } 184 | 185 | RequestSigner.prototype.getDateTime = function() { 186 | if (!this.datetime) { 187 | var headers = this.request.headers, 188 | date = new Date(headers.Date || headers.date || new Date) 189 | 190 | this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, '') 191 | 192 | // Remove the trailing 'Z' on the timestamp string for CodeCommit git access 193 | if (this.isCodeCommitGit) this.datetime = this.datetime.slice(0, -1) 194 | } 195 | return this.datetime 196 | } 197 | 198 | RequestSigner.prototype.getDate = function() { 199 | return this.getDateTime().substr(0, 8) 200 | } 201 | 202 | RequestSigner.prototype.authHeader = function() { 203 | return [ 204 | 'AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(), 205 | 'SignedHeaders=' + this.signedHeaders(), 206 | 'Signature=' + this.signature(), 207 | ].join(', ') 208 | } 209 | 210 | RequestSigner.prototype.signature = function() { 211 | var date = this.getDate(), 212 | cacheKey = [this.credentials.secretAccessKey, date, this.region, this.service].join(), 213 | kDate, kRegion, kService, kCredentials = credentialsCache.get(cacheKey) 214 | if (!kCredentials) { 215 | kDate = hmac('AWS4' + this.credentials.secretAccessKey, date) 216 | kRegion = hmac(kDate, this.region) 217 | kService = hmac(kRegion, this.service) 218 | kCredentials = hmac(kService, 'aws4_request') 219 | credentialsCache.set(cacheKey, kCredentials) 220 | } 221 | return hmac(kCredentials, this.stringToSign(), 'hex') 222 | } 223 | 224 | RequestSigner.prototype.stringToSign = function() { 225 | return [ 226 | 'AWS4-HMAC-SHA256', 227 | this.getDateTime(), 228 | this.credentialString(), 229 | hash(this.canonicalString(), 'hex'), 230 | ].join('\n') 231 | } 232 | 233 | RequestSigner.prototype.canonicalString = function() { 234 | if (!this.parsedPath) this.prepareRequest() 235 | 236 | var pathStr = this.parsedPath.path, 237 | query = this.parsedPath.query, 238 | headers = this.request.headers, 239 | queryStr = '', 240 | normalizePath = this.service !== 's3', 241 | decodePath = this.service === 's3' || this.request.doNotEncodePath, 242 | decodeSlashesInPath = this.service === 's3', 243 | firstValOnly = this.service === 's3', 244 | bodyHash 245 | 246 | if (this.service === 's3' && this.request.signQuery) { 247 | bodyHash = 'UNSIGNED-PAYLOAD' 248 | } else if (this.isCodeCommitGit) { 249 | bodyHash = '' 250 | } else { 251 | bodyHash = headers['X-Amz-Content-Sha256'] || headers['x-amz-content-sha256'] || 252 | hash(this.request.body || '', 'hex') 253 | } 254 | 255 | if (query) { 256 | var reducedQuery = Object.keys(query).reduce(function(obj, key) { 257 | if (!key) return obj 258 | obj[encodeRfc3986Full(key)] = !Array.isArray(query[key]) ? query[key] : 259 | (firstValOnly ? query[key][0] : query[key]) 260 | return obj 261 | }, {}) 262 | var encodedQueryPieces = [] 263 | Object.keys(reducedQuery).sort().forEach(function(key) { 264 | if (!Array.isArray(reducedQuery[key])) { 265 | encodedQueryPieces.push(key + '=' + encodeRfc3986Full(reducedQuery[key])) 266 | } else { 267 | reducedQuery[key].map(encodeRfc3986Full).sort() 268 | .forEach(function(val) { encodedQueryPieces.push(key + '=' + val) }) 269 | } 270 | }) 271 | queryStr = encodedQueryPieces.join('&') 272 | } 273 | if (pathStr !== '/') { 274 | if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/') 275 | pathStr = pathStr.split('/').reduce(function(path, piece) { 276 | if (normalizePath && piece === '..') { 277 | path.pop() 278 | } else if (!normalizePath || piece !== '.') { 279 | if (decodePath) piece = decodeURIComponent(piece.replace(/\+/g, ' ')) 280 | path.push(encodeRfc3986Full(piece)) 281 | } 282 | return path 283 | }, []).join('/') 284 | if (pathStr[0] !== '/') pathStr = '/' + pathStr 285 | if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/') 286 | } 287 | 288 | return [ 289 | this.request.method || 'GET', 290 | pathStr, 291 | queryStr, 292 | this.canonicalHeaders() + '\n', 293 | this.signedHeaders(), 294 | bodyHash, 295 | ].join('\n') 296 | } 297 | 298 | RequestSigner.prototype.filterHeaders = function() { 299 | var headers = this.request.headers, 300 | extraHeadersToInclude = this.extraHeadersToInclude, 301 | extraHeadersToIgnore = this.extraHeadersToIgnore 302 | this.filteredHeaders = Object.keys(headers) 303 | .map(function(key) { return [key.toLowerCase(), headers[key]] }) 304 | .filter(function(entry) { 305 | return extraHeadersToInclude[entry[0]] || 306 | (HEADERS_TO_IGNORE[entry[0]] == null && !extraHeadersToIgnore[entry[0]]) 307 | }) 308 | .sort(function(a, b) { return a[0] < b[0] ? -1 : 1 }) 309 | } 310 | 311 | RequestSigner.prototype.canonicalHeaders = function() { 312 | if (!this.filteredHeaders) this.filterHeaders() 313 | 314 | return this.filteredHeaders.map(function(entry) { 315 | return entry[0] + ':' + entry[1].toString().trim().replace(/\s+/g, ' ') 316 | }).join('\n') 317 | } 318 | 319 | RequestSigner.prototype.signedHeaders = function() { 320 | if (!this.filteredHeaders) this.filterHeaders() 321 | 322 | return this.filteredHeaders.map(function(entry) { return entry[0] }).join(';') 323 | } 324 | 325 | RequestSigner.prototype.credentialString = function() { 326 | return [ 327 | this.getDate(), 328 | this.region, 329 | this.service, 330 | 'aws4_request', 331 | ].join('/') 332 | } 333 | 334 | RequestSigner.prototype.defaultCredentials = function() { 335 | var env = process.env 336 | return { 337 | accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY, 338 | secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY, 339 | sessionToken: env.AWS_SESSION_TOKEN, 340 | } 341 | } 342 | 343 | RequestSigner.prototype.parsePath = function() { 344 | var path = this.request.path || '/' 345 | 346 | // S3 doesn't always encode characters > 127 correctly and 347 | // all services don't encode characters > 255 correctly 348 | // So if there are non-reserved chars (and it's not already all % encoded), just encode them all 349 | if (/[^0-9A-Za-z;,/?:@&=+$\-_.!~*'()#%]/.test(path)) { 350 | path = encodeURI(decodeURI(path)) 351 | } 352 | 353 | var queryIx = path.indexOf('?'), 354 | query = null 355 | 356 | if (queryIx >= 0) { 357 | query = querystring.parse(path.slice(queryIx + 1)) 358 | path = path.slice(0, queryIx) 359 | } 360 | 361 | this.parsedPath = { 362 | path: path, 363 | query: query, 364 | } 365 | } 366 | 367 | RequestSigner.prototype.formatPath = function() { 368 | var path = this.parsedPath.path, 369 | query = this.parsedPath.query 370 | 371 | if (!query) return path 372 | 373 | // Services don't support empty query string keys 374 | if (query[''] != null) delete query[''] 375 | 376 | return path + '?' + encodeRfc3986(querystring.stringify(query)) 377 | } 378 | 379 | aws4.RequestSigner = RequestSigner 380 | 381 | aws4.sign = function(request, credentials) { 382 | return new RequestSigner(request, credentials).sign() 383 | } 384 | -------------------------------------------------------------------------------- /browser/README.md: -------------------------------------------------------------------------------- 1 | Browser aws4 example 2 | -------------------- 3 | 4 | This is one way to use `aws4` in the browser – using [browserify](http://browserify.org/). 5 | 6 | The example JS code that uses `aws4` is in `index.js`: 7 | 8 | ```js 9 | var aws4 = require('aws4') 10 | 11 | var CREDS = { accessKeyId: 'a', secretAccessKey: 'b' } 12 | 13 | var sigs = { 14 | s3: aws4.sign({ host: 'my-bucket.s3.amazonaws.com', path: '/whatever?X-Amz-Expires=1234', signQuery: true }, CREDS), 15 | sqs: aws4.sign({ service: 'sqs' }, CREDS), 16 | codedeploy: aws4.sign({ service: 'codedeploy', body: '{}', headers: { 17 | 'Content-Type': 'application/x-amz-json-1.1', 18 | 'X-Amz-Target': 'CodeDeploy_20141006.ListApplications', 19 | } }, CREDS), 20 | } 21 | 22 | document.getElementById('content').innerHTML = JSON.stringify(sigs, null, 2) 23 | ``` 24 | 25 | To compile this, checkout this directory and run: 26 | 27 | ```console 28 | $ npm install 29 | $ npm run build 30 | ``` 31 | 32 | Then open `index.html` where you should see the signed requests that were specified in `index.js` 33 | 34 | -------------------------------------------------------------------------------- /browser/index.html: -------------------------------------------------------------------------------- 1 |

aws4 Signature Examples

2 |
3 | 
4 | 


--------------------------------------------------------------------------------
/browser/index.js:
--------------------------------------------------------------------------------
 1 | var aws4 = require('aws4')
 2 | 
 3 | var CREDS = { accessKeyId: 'a', secretAccessKey: 'b' }
 4 | 
 5 | var sigs = {
 6 |   s3: aws4.sign({ host: 'my-bucket.s3.amazonaws.com', path: '/whatever?X-Amz-Expires=1234', signQuery: true }, CREDS),
 7 |   sqs: aws4.sign({ service: 'sqs' }, CREDS),
 8 |   codedeploy: aws4.sign({ service: 'codedeploy', body: '{}', headers: {
 9 |     'Content-Type': 'application/x-amz-json-1.1',
10 |     'X-Amz-Target': 'CodeDeploy_20141006.ListApplications',
11 |   } }, CREDS),
12 | }
13 | 
14 | document.getElementById('content').innerHTML = JSON.stringify(sigs, null, 2)
15 | 


--------------------------------------------------------------------------------
/browser/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "aws4-browser-example",
 3 |   "version": "1.0.0",
 4 |   "description": "Example project for how to use aws4 in the browser",
 5 |   "main": "index.js",
 6 |   "author": "Michael Hart  (http://github.com/mhart)",
 7 |   "license": "ISC",
 8 |   "scripts": {
 9 |     "build": "browserify -o bundle.js index.js"
10 |   },
11 |   "dependencies": {
12 |     "aws4": "^1.13.2"
13 |   },
14 |   "devDependencies": {
15 |     "browserify": "^17.0.0"
16 |   }
17 | }
18 | 


--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
  1 | var http = require('https')
  2 | var aws4  = require('.')
  3 | 
  4 | // to illustrate usage, we'll create a utility function to request and pipe to stdout
  5 | function request(opts) { http.request(opts, function(res) { res.pipe(process.stdout) }).end(opts.body || '') }
  6 | 
  7 | // aws4 will sign an options object as you'd pass to http.request, with an AWS service and region
  8 | var opts = { host: 'my-bucket.s3.us-west-1.amazonaws.com', path: '/my-object', service: 's3', region: 'us-west-1' }
  9 | 
 10 | // aws4.sign() will sign and modify these options, ready to pass to http.request
 11 | aws4.sign(opts, { accessKeyId: '', secretAccessKey: '' })
 12 | 
 13 | // or it can get credentials from process.env.AWS_ACCESS_KEY_ID, etc
 14 | aws4.sign(opts)
 15 | 
 16 | // for most AWS services, aws4 can figure out the service and region if you pass a host
 17 | opts = { host: 'my-bucket.s3.us-west-1.amazonaws.com', path: '/my-object' }
 18 | 
 19 | // usually it will add/modify request headers, but you can also sign the query:
 20 | opts = { host: 'my-bucket.s3.amazonaws.com', path: '/?X-Amz-Expires=12345', signQuery: true }
 21 | 
 22 | // and for services with simple hosts, aws4 can infer the host from service and region:
 23 | opts = { service: 'sqs', region: 'us-east-1', path: '/?Action=ListQueues' }
 24 | 
 25 | // and if you're using us-east-1, it's the default:
 26 | opts = { service: 'sqs', path: '/?Action=ListQueues' }
 27 | 
 28 | aws4.sign(opts)
 29 | console.log(opts)
 30 | /*
 31 | {
 32 |   host: 'sqs.us-east-1.amazonaws.com',
 33 |   path: '/?Action=ListQueues',
 34 |   headers: {
 35 |     Host: 'sqs.us-east-1.amazonaws.com',
 36 |     'X-Amz-Date': '20121226T061030Z',
 37 |     Authorization: 'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/sqs/aws4_request, ...'
 38 |   }
 39 | }
 40 | */
 41 | 
 42 | // we can now use this to query AWS
 43 | request(opts)
 44 | /*
 45 | 
 46 | 
 47 | ...
 48 | */
 49 | 
 50 | // aws4 can infer the HTTP method if a body is passed in
 51 | // method will be POST and Content-Type: 'application/x-www-form-urlencoded; charset=utf-8'
 52 | request(aws4.sign({ service: 'iam', body: 'Action=ListGroups&Version=2010-05-08' }))
 53 | /*
 54 | 
 55 | ...
 56 | */
 57 | 
 58 | // you can specify any custom option or header as per usual
 59 | request(aws4.sign({
 60 |   service: 'dynamodb',
 61 |   region: 'ap-southeast-2',
 62 |   method: 'POST',
 63 |   path: '/',
 64 |   headers: {
 65 |     'Content-Type': 'application/x-amz-json-1.0',
 66 |     'X-Amz-Target': 'DynamoDB_20120810.ListTables'
 67 |   },
 68 |   body: '{}'
 69 | }))
 70 | /*
 71 | {"TableNames":[]}
 72 | ...
 73 | */
 74 | 
 75 | // works with all other services that support Signature Version 4
 76 | 
 77 | request(aws4.sign({ service: 's3', path: '/', signQuery: true }))
 78 | /*
 79 | 
 80 | ...
 81 | */
 82 | 
 83 | request(aws4.sign({ service: 'ec2', path: '/?Action=DescribeRegions&Version=2014-06-15' }))
 84 | /*
 85 | 
 86 | ...
 87 | */
 88 | 
 89 | request(aws4.sign({ service: 'sns', path: '/?Action=ListTopics&Version=2010-03-31' }))
 90 | /*
 91 | 
 92 | ...
 93 | */
 94 | 
 95 | request(aws4.sign({ service: 'sts', path: '/?Action=GetSessionToken&Version=2011-06-15' }))
 96 | /*
 97 | 
 98 | ...
 99 | */
100 | 
101 | request(aws4.sign({ service: 'cloudsearch', path: '/?Action=ListDomainNames&Version=2013-01-01' }))
102 | /*
103 | 
104 | ...
105 | */
106 | 
107 | request(aws4.sign({ service: 'ses', path: '/?Action=ListIdentities&Version=2010-12-01' }))
108 | /*
109 | 
110 | ...
111 | */
112 | 
113 | request(aws4.sign({ service: 'autoscaling', path: '/?Action=DescribeAutoScalingInstances&Version=2011-01-01' }))
114 | /*
115 | 
116 | ...
117 | */
118 | 
119 | request(aws4.sign({ service: 'elasticloadbalancing', path: '/?Action=DescribeLoadBalancers&Version=2012-06-01' }))
120 | /*
121 | 
122 | ...
123 | */
124 | 
125 | request(aws4.sign({ service: 'cloudformation', path: '/?Action=ListStacks&Version=2010-05-15' }))
126 | /*
127 | 
128 | ...
129 | */
130 | 
131 | request(aws4.sign({ service: 'elasticbeanstalk', path: '/?Action=ListAvailableSolutionStacks&Version=2010-12-01' }))
132 | /*
133 | 
134 | ...
135 | */
136 | 
137 | request(aws4.sign({ service: 'rds', path: '/?Action=DescribeDBInstances&Version=2012-09-17' }))
138 | /*
139 | 
140 | ...
141 | */
142 | 
143 | request(aws4.sign({ service: 'monitoring', path: '/?Action=ListMetrics&Version=2010-08-01' }))
144 | /*
145 | 
146 | ...
147 | */
148 | 
149 | request(aws4.sign({ service: 'redshift', path: '/?Action=DescribeClusters&Version=2012-12-01' }))
150 | /*
151 | 
152 | ...
153 | */
154 | 
155 | request(aws4.sign({ service: 'cloudfront', path: '/2014-05-31/distribution' }))
156 | /*
157 | 
158 | ...
159 | */
160 | 
161 | request(aws4.sign({ service: 'elasticache', path: '/?Action=DescribeCacheClusters&Version=2014-07-15' }))
162 | /*
163 | 
164 | ...
165 | */
166 | 
167 | request(aws4.sign({ service: 'elasticmapreduce', path: '/?Action=DescribeJobFlows&Version=2009-03-31' }))
168 | /*
169 | 
170 | ...
171 | */
172 | 
173 | request(aws4.sign({ service: 'route53', path: '/2013-04-01/hostedzone' }))
174 | /*
175 | 
176 | ...
177 | */
178 | 
179 | request(aws4.sign({ service: 'cognito-sync', path: '/identitypools' }))
180 | /*
181 | {"Count":0,"IdentityPoolUsages":[],"MaxResults":16,"NextToken":null}
182 | ...
183 | */
184 | 
185 | request(aws4.sign({ service: 'elastictranscoder', path: '/2012-09-25/pipelines' }))
186 | /*
187 | {"NextPageToken":null,"Pipelines":[]}
188 | ...
189 | */
190 | 
191 | request(aws4.sign({ service: 'lambda', path: '/2014-11-13/functions/' }))
192 | /*
193 | {"Functions":[],"NextMarker":null}
194 | ...
195 | */
196 | 
197 | request(aws4.sign({ service: 'ecs', path: '/?Action=ListClusters&Version=2014-11-13' }))
198 | /*
199 | 
200 | ...
201 | */
202 | 
203 | request(aws4.sign({ service: 'glacier', path: '/-/vaults', headers: { 'X-Amz-Glacier-Version': '2012-06-01' } }))
204 | /*
205 | {"Marker":null,"VaultList":[]}
206 | ...
207 | */
208 | 
209 | request(aws4.sign({ service: 'storagegateway', body: '{}', headers: {
210 |   'Content-Type': 'application/x-amz-json-1.1',
211 |   'X-Amz-Target': 'StorageGateway_20120630.ListGateways'
212 | } }))
213 | /*
214 | {"Gateways":[]}
215 | ...
216 | */
217 | 
218 | request(aws4.sign({ service: 'datapipeline', body: '{}', headers: {
219 |   'Content-Type': 'application/x-amz-json-1.1',
220 |   'X-Amz-Target': 'DataPipeline.ListPipelines'
221 | } }))
222 | /*
223 | {"hasMoreResults":false,"pipelineIdList":[]}
224 | ...
225 | */
226 | 
227 | request(aws4.sign({ service: 'opsworks', body: '{}', headers: {
228 |   'Content-Type': 'application/x-amz-json-1.1',
229 |   'X-Amz-Target': 'OpsWorks_20130218.DescribeStacks'
230 | } }))
231 | /*
232 | {"Stacks":[]}
233 | ...
234 | */
235 | 
236 | request(aws4.sign({ service: 'route53domains', body: '{}', headers: {
237 |   'Content-Type': 'application/x-amz-json-1.1',
238 |   'X-Amz-Target': 'Route53Domains_v20140515.ListDomains'
239 | } }))
240 | /*
241 | {"Domains":[]}
242 | ...
243 | */
244 | 
245 | request(aws4.sign({ service: 'kinesis', body: '{}', headers: {
246 |   'Content-Type': 'application/x-amz-json-1.1',
247 |   'X-Amz-Target': 'Kinesis_20131202.ListStreams'
248 | } }))
249 | /*
250 | {"HasMoreStreams":false,"StreamNames":[]}
251 | ...
252 | */
253 | 
254 | request(aws4.sign({ service: 'cloudtrail', body: '{}', headers: {
255 |   'Content-Type': 'application/x-amz-json-1.1',
256 |   'X-Amz-Target': 'CloudTrail_20131101.DescribeTrails'
257 | } }))
258 | /*
259 | {"trailList":[]}
260 | ...
261 | */
262 | 
263 | request(aws4.sign({ service: 'logs', body: '{}', headers: {
264 |   'Content-Type': 'application/x-amz-json-1.1',
265 |   'X-Amz-Target': 'Logs_20140328.DescribeLogGroups'
266 | } }))
267 | /*
268 | {"logGroups":[]}
269 | ...
270 | */
271 | 
272 | request(aws4.sign({ service: 'codedeploy', body: '{}', headers: {
273 |   'Content-Type': 'application/x-amz-json-1.1',
274 |   'X-Amz-Target': 'CodeDeploy_20141006.ListApplications'
275 | } }))
276 | /*
277 | {"applications":[]}
278 | ...
279 | */
280 | 
281 | request(aws4.sign({ service: 'directconnect', body: '{}', headers: {
282 |   'Content-Type': 'application/x-amz-json-1.1',
283 |   'X-Amz-Target': 'OvertureService.DescribeConnections'
284 | } }))
285 | /*
286 | {"connections":[]}
287 | ...
288 | */
289 | 
290 | request(aws4.sign({ service: 'kms', body: '{}', headers: {
291 |   'Content-Type': 'application/x-amz-json-1.1',
292 |   'X-Amz-Target': 'TrentService.ListKeys'
293 | } }))
294 | /*
295 | {"Keys":[],"Truncated":false}
296 | ...
297 | */
298 | 
299 | request(aws4.sign({ service: 'config', body: '{}', headers: {
300 |   'Content-Type': 'application/x-amz-json-1.1',
301 |   'X-Amz-Target': 'StarlingDoveService.DescribeDeliveryChannels'
302 | } }))
303 | /*
304 | {"DeliveryChannels":[]}
305 | ...
306 | */
307 | 
308 | request(aws4.sign({ service: 'cloudhsm', body: '{}', headers: {
309 |   'Content-Type': 'application/x-amz-json-1.1',
310 |   'X-Amz-Target': 'CloudHsmFrontendService.ListAvailableZones'
311 | } }))
312 | /*
313 | {"AZList":["us-east-1a","us-east-1b","us-east-1c"]}
314 | ...
315 | */
316 | 
317 | request(aws4.sign({
318 |   service: 'swf',
319 |   body: '{"registrationStatus":"REGISTERED"}',
320 |   headers: {
321 |     'Content-Type': 'application/x-amz-json-1.0',
322 |     'X-Amz-Target': 'SimpleWorkflowService.ListDomains'
323 |   }
324 | }))
325 | /*
326 | {"domainInfos":[]}
327 | ...
328 | */
329 | 
330 | request(aws4.sign({
331 |   service: 'cognito-identity',
332 |   body: '{"MaxResults": 1}',
333 |   headers: {
334 |     'Content-Type': 'application/x-amz-json-1.1',
335 |     'X-Amz-Target': 'AWSCognitoIdentityService.ListIdentityPools'
336 |   }
337 | }))
338 | /*
339 | {"IdentityPools":[]}
340 | ...
341 | */
342 | 
343 | request(aws4.sign({
344 |   service: 'mobileanalytics',
345 |   path: '/2014-06-05/events',
346 |   body: JSON.stringify({ events: [{
347 |     eventType: 'a',
348 |     timestamp: new Date().toISOString(),
349 |     session: {},
350 |   }] }),
351 |   headers: {
352 |     'Content-Type': 'application/json',
353 |     'X-Amz-Client-Context': JSON.stringify({
354 |       client: { client_id: 'a', app_title: 'a' },
355 |       custom: {},
356 |       env: { platform: 'a' },
357 |       services: {},
358 |     }),
359 |   }
360 | }))
361 | /*
362 | (HTTP 202, empty response)
363 | */
364 | 


--------------------------------------------------------------------------------
/lru.js:
--------------------------------------------------------------------------------
 1 | module.exports = function(size) {
 2 |   return new LruCache(size)
 3 | }
 4 | 
 5 | function LruCache(size) {
 6 |   this.capacity = size | 0
 7 |   this.map = Object.create(null)
 8 |   this.list = new DoublyLinkedList()
 9 | }
10 | 
11 | LruCache.prototype.get = function(key) {
12 |   var node = this.map[key]
13 |   if (node == null) return undefined
14 |   this.used(node)
15 |   return node.val
16 | }
17 | 
18 | LruCache.prototype.set = function(key, val) {
19 |   var node = this.map[key]
20 |   if (node != null) {
21 |     node.val = val
22 |   } else {
23 |     if (!this.capacity) this.prune()
24 |     if (!this.capacity) return false
25 |     node = new DoublyLinkedNode(key, val)
26 |     this.map[key] = node
27 |     this.capacity--
28 |   }
29 |   this.used(node)
30 |   return true
31 | }
32 | 
33 | LruCache.prototype.used = function(node) {
34 |   this.list.moveToFront(node)
35 | }
36 | 
37 | LruCache.prototype.prune = function() {
38 |   var node = this.list.pop()
39 |   if (node != null) {
40 |     delete this.map[node.key]
41 |     this.capacity++
42 |   }
43 | }
44 | 
45 | 
46 | function DoublyLinkedList() {
47 |   this.firstNode = null
48 |   this.lastNode = null
49 | }
50 | 
51 | DoublyLinkedList.prototype.moveToFront = function(node) {
52 |   if (this.firstNode == node) return
53 | 
54 |   this.remove(node)
55 | 
56 |   if (this.firstNode == null) {
57 |     this.firstNode = node
58 |     this.lastNode = node
59 |     node.prev = null
60 |     node.next = null
61 |   } else {
62 |     node.prev = null
63 |     node.next = this.firstNode
64 |     node.next.prev = node
65 |     this.firstNode = node
66 |   }
67 | }
68 | 
69 | DoublyLinkedList.prototype.pop = function() {
70 |   var lastNode = this.lastNode
71 |   if (lastNode != null) {
72 |     this.remove(lastNode)
73 |   }
74 |   return lastNode
75 | }
76 | 
77 | DoublyLinkedList.prototype.remove = function(node) {
78 |   if (this.firstNode == node) {
79 |     this.firstNode = node.next
80 |   } else if (node.prev != null) {
81 |     node.prev.next = node.next
82 |   }
83 |   if (this.lastNode == node) {
84 |     this.lastNode = node.prev
85 |   } else if (node.next != null) {
86 |     node.next.prev = node.prev
87 |   }
88 | }
89 | 
90 | 
91 | function DoublyLinkedNode(key, val) {
92 |   this.key = key
93 |   this.val = val
94 |   this.prev = null
95 |   this.next = null
96 | }
97 | 


--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
  1 | {
  2 |   "name": "aws4",
  3 |   "version": "1.13.2",
  4 |   "lockfileVersion": 3,
  5 |   "requires": true,
  6 |   "packages": {
  7 |     "": {
  8 |       "name": "aws4",
  9 |       "version": "1.13.2",
 10 |       "license": "MIT",
 11 |       "devDependencies": {
 12 |         "mocha": "^10.7.3",
 13 |         "should": "^13.2.3"
 14 |       }
 15 |     },
 16 |     "node_modules/ansi-colors": {
 17 |       "version": "4.1.3",
 18 |       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
 19 |       "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
 20 |       "dev": true,
 21 |       "license": "MIT",
 22 |       "engines": {
 23 |         "node": ">=6"
 24 |       }
 25 |     },
 26 |     "node_modules/ansi-regex": {
 27 |       "version": "5.0.1",
 28 |       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
 29 |       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
 30 |       "dev": true,
 31 |       "engines": {
 32 |         "node": ">=8"
 33 |       }
 34 |     },
 35 |     "node_modules/ansi-styles": {
 36 |       "version": "4.3.0",
 37 |       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
 38 |       "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
 39 |       "dev": true,
 40 |       "dependencies": {
 41 |         "color-convert": "^2.0.1"
 42 |       },
 43 |       "engines": {
 44 |         "node": ">=8"
 45 |       },
 46 |       "funding": {
 47 |         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
 48 |       }
 49 |     },
 50 |     "node_modules/anymatch": {
 51 |       "version": "3.1.3",
 52 |       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
 53 |       "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
 54 |       "dev": true,
 55 |       "dependencies": {
 56 |         "normalize-path": "^3.0.0",
 57 |         "picomatch": "^2.0.4"
 58 |       },
 59 |       "engines": {
 60 |         "node": ">= 8"
 61 |       }
 62 |     },
 63 |     "node_modules/argparse": {
 64 |       "version": "2.0.1",
 65 |       "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
 66 |       "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
 67 |       "dev": true
 68 |     },
 69 |     "node_modules/balanced-match": {
 70 |       "version": "1.0.2",
 71 |       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 72 |       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
 73 |       "dev": true
 74 |     },
 75 |     "node_modules/binary-extensions": {
 76 |       "version": "2.2.0",
 77 |       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
 78 |       "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
 79 |       "dev": true,
 80 |       "engines": {
 81 |         "node": ">=8"
 82 |       }
 83 |     },
 84 |     "node_modules/brace-expansion": {
 85 |       "version": "2.0.1",
 86 |       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
 87 |       "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
 88 |       "dev": true,
 89 |       "dependencies": {
 90 |         "balanced-match": "^1.0.0"
 91 |       }
 92 |     },
 93 |     "node_modules/braces": {
 94 |       "version": "3.0.3",
 95 |       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
 96 |       "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
 97 |       "dev": true,
 98 |       "license": "MIT",
 99 |       "dependencies": {
100 |         "fill-range": "^7.1.1"
101 |       },
102 |       "engines": {
103 |         "node": ">=8"
104 |       }
105 |     },
106 |     "node_modules/browser-stdout": {
107 |       "version": "1.3.1",
108 |       "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
109 |       "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
110 |       "dev": true
111 |     },
112 |     "node_modules/camelcase": {
113 |       "version": "6.3.0",
114 |       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
115 |       "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
116 |       "dev": true,
117 |       "engines": {
118 |         "node": ">=10"
119 |       },
120 |       "funding": {
121 |         "url": "https://github.com/sponsors/sindresorhus"
122 |       }
123 |     },
124 |     "node_modules/chalk": {
125 |       "version": "4.1.2",
126 |       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
127 |       "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
128 |       "dev": true,
129 |       "dependencies": {
130 |         "ansi-styles": "^4.1.0",
131 |         "supports-color": "^7.1.0"
132 |       },
133 |       "engines": {
134 |         "node": ">=10"
135 |       },
136 |       "funding": {
137 |         "url": "https://github.com/chalk/chalk?sponsor=1"
138 |       }
139 |     },
140 |     "node_modules/chalk/node_modules/supports-color": {
141 |       "version": "7.2.0",
142 |       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
143 |       "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
144 |       "dev": true,
145 |       "dependencies": {
146 |         "has-flag": "^4.0.0"
147 |       },
148 |       "engines": {
149 |         "node": ">=8"
150 |       }
151 |     },
152 |     "node_modules/chokidar": {
153 |       "version": "3.5.3",
154 |       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
155 |       "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
156 |       "dev": true,
157 |       "funding": [
158 |         {
159 |           "type": "individual",
160 |           "url": "https://paulmillr.com/funding/"
161 |         }
162 |       ],
163 |       "dependencies": {
164 |         "anymatch": "~3.1.2",
165 |         "braces": "~3.0.2",
166 |         "glob-parent": "~5.1.2",
167 |         "is-binary-path": "~2.1.0",
168 |         "is-glob": "~4.0.1",
169 |         "normalize-path": "~3.0.0",
170 |         "readdirp": "~3.6.0"
171 |       },
172 |       "engines": {
173 |         "node": ">= 8.10.0"
174 |       },
175 |       "optionalDependencies": {
176 |         "fsevents": "~2.3.2"
177 |       }
178 |     },
179 |     "node_modules/cliui": {
180 |       "version": "7.0.4",
181 |       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
182 |       "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
183 |       "dev": true,
184 |       "dependencies": {
185 |         "string-width": "^4.2.0",
186 |         "strip-ansi": "^6.0.0",
187 |         "wrap-ansi": "^7.0.0"
188 |       }
189 |     },
190 |     "node_modules/color-convert": {
191 |       "version": "2.0.1",
192 |       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
193 |       "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
194 |       "dev": true,
195 |       "dependencies": {
196 |         "color-name": "~1.1.4"
197 |       },
198 |       "engines": {
199 |         "node": ">=7.0.0"
200 |       }
201 |     },
202 |     "node_modules/color-name": {
203 |       "version": "1.1.4",
204 |       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
205 |       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
206 |       "dev": true
207 |     },
208 |     "node_modules/debug": {
209 |       "version": "4.3.6",
210 |       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
211 |       "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
212 |       "dev": true,
213 |       "license": "MIT",
214 |       "dependencies": {
215 |         "ms": "2.1.2"
216 |       },
217 |       "engines": {
218 |         "node": ">=6.0"
219 |       },
220 |       "peerDependenciesMeta": {
221 |         "supports-color": {
222 |           "optional": true
223 |         }
224 |       }
225 |     },
226 |     "node_modules/debug/node_modules/ms": {
227 |       "version": "2.1.2",
228 |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
229 |       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
230 |       "dev": true,
231 |       "license": "MIT"
232 |     },
233 |     "node_modules/decamelize": {
234 |       "version": "4.0.0",
235 |       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
236 |       "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
237 |       "dev": true,
238 |       "engines": {
239 |         "node": ">=10"
240 |       },
241 |       "funding": {
242 |         "url": "https://github.com/sponsors/sindresorhus"
243 |       }
244 |     },
245 |     "node_modules/diff": {
246 |       "version": "5.2.0",
247 |       "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
248 |       "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
249 |       "dev": true,
250 |       "license": "BSD-3-Clause",
251 |       "engines": {
252 |         "node": ">=0.3.1"
253 |       }
254 |     },
255 |     "node_modules/emoji-regex": {
256 |       "version": "8.0.0",
257 |       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
258 |       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
259 |       "dev": true
260 |     },
261 |     "node_modules/escalade": {
262 |       "version": "3.1.2",
263 |       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
264 |       "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
265 |       "dev": true,
266 |       "engines": {
267 |         "node": ">=6"
268 |       }
269 |     },
270 |     "node_modules/escape-string-regexp": {
271 |       "version": "4.0.0",
272 |       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
273 |       "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
274 |       "dev": true,
275 |       "engines": {
276 |         "node": ">=10"
277 |       },
278 |       "funding": {
279 |         "url": "https://github.com/sponsors/sindresorhus"
280 |       }
281 |     },
282 |     "node_modules/fill-range": {
283 |       "version": "7.1.1",
284 |       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
285 |       "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
286 |       "dev": true,
287 |       "license": "MIT",
288 |       "dependencies": {
289 |         "to-regex-range": "^5.0.1"
290 |       },
291 |       "engines": {
292 |         "node": ">=8"
293 |       }
294 |     },
295 |     "node_modules/find-up": {
296 |       "version": "5.0.0",
297 |       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
298 |       "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
299 |       "dev": true,
300 |       "dependencies": {
301 |         "locate-path": "^6.0.0",
302 |         "path-exists": "^4.0.0"
303 |       },
304 |       "engines": {
305 |         "node": ">=10"
306 |       },
307 |       "funding": {
308 |         "url": "https://github.com/sponsors/sindresorhus"
309 |       }
310 |     },
311 |     "node_modules/flat": {
312 |       "version": "5.0.2",
313 |       "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
314 |       "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
315 |       "dev": true,
316 |       "bin": {
317 |         "flat": "cli.js"
318 |       }
319 |     },
320 |     "node_modules/fs.realpath": {
321 |       "version": "1.0.0",
322 |       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
323 |       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
324 |       "dev": true
325 |     },
326 |     "node_modules/fsevents": {
327 |       "version": "2.3.3",
328 |       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
329 |       "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
330 |       "dev": true,
331 |       "hasInstallScript": true,
332 |       "optional": true,
333 |       "os": [
334 |         "darwin"
335 |       ],
336 |       "engines": {
337 |         "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
338 |       }
339 |     },
340 |     "node_modules/get-caller-file": {
341 |       "version": "2.0.5",
342 |       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
343 |       "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
344 |       "dev": true,
345 |       "engines": {
346 |         "node": "6.* || 8.* || >= 10.*"
347 |       }
348 |     },
349 |     "node_modules/glob": {
350 |       "version": "8.1.0",
351 |       "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
352 |       "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
353 |       "dev": true,
354 |       "dependencies": {
355 |         "fs.realpath": "^1.0.0",
356 |         "inflight": "^1.0.4",
357 |         "inherits": "2",
358 |         "minimatch": "^5.0.1",
359 |         "once": "^1.3.0"
360 |       },
361 |       "engines": {
362 |         "node": ">=12"
363 |       },
364 |       "funding": {
365 |         "url": "https://github.com/sponsors/isaacs"
366 |       }
367 |     },
368 |     "node_modules/glob-parent": {
369 |       "version": "5.1.2",
370 |       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
371 |       "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
372 |       "dev": true,
373 |       "dependencies": {
374 |         "is-glob": "^4.0.1"
375 |       },
376 |       "engines": {
377 |         "node": ">= 6"
378 |       }
379 |     },
380 |     "node_modules/has-flag": {
381 |       "version": "4.0.0",
382 |       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
383 |       "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
384 |       "dev": true,
385 |       "engines": {
386 |         "node": ">=8"
387 |       }
388 |     },
389 |     "node_modules/he": {
390 |       "version": "1.2.0",
391 |       "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
392 |       "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
393 |       "dev": true,
394 |       "bin": {
395 |         "he": "bin/he"
396 |       }
397 |     },
398 |     "node_modules/inflight": {
399 |       "version": "1.0.6",
400 |       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
401 |       "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
402 |       "dev": true,
403 |       "dependencies": {
404 |         "once": "^1.3.0",
405 |         "wrappy": "1"
406 |       }
407 |     },
408 |     "node_modules/inherits": {
409 |       "version": "2.0.4",
410 |       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
411 |       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
412 |       "dev": true
413 |     },
414 |     "node_modules/is-binary-path": {
415 |       "version": "2.1.0",
416 |       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
417 |       "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
418 |       "dev": true,
419 |       "dependencies": {
420 |         "binary-extensions": "^2.0.0"
421 |       },
422 |       "engines": {
423 |         "node": ">=8"
424 |       }
425 |     },
426 |     "node_modules/is-extglob": {
427 |       "version": "2.1.1",
428 |       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
429 |       "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
430 |       "dev": true,
431 |       "engines": {
432 |         "node": ">=0.10.0"
433 |       }
434 |     },
435 |     "node_modules/is-fullwidth-code-point": {
436 |       "version": "3.0.0",
437 |       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
438 |       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
439 |       "dev": true,
440 |       "engines": {
441 |         "node": ">=8"
442 |       }
443 |     },
444 |     "node_modules/is-glob": {
445 |       "version": "4.0.3",
446 |       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
447 |       "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
448 |       "dev": true,
449 |       "dependencies": {
450 |         "is-extglob": "^2.1.1"
451 |       },
452 |       "engines": {
453 |         "node": ">=0.10.0"
454 |       }
455 |     },
456 |     "node_modules/is-number": {
457 |       "version": "7.0.0",
458 |       "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
459 |       "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
460 |       "dev": true,
461 |       "license": "MIT",
462 |       "engines": {
463 |         "node": ">=0.12.0"
464 |       }
465 |     },
466 |     "node_modules/is-plain-obj": {
467 |       "version": "2.1.0",
468 |       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
469 |       "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
470 |       "dev": true,
471 |       "engines": {
472 |         "node": ">=8"
473 |       }
474 |     },
475 |     "node_modules/is-unicode-supported": {
476 |       "version": "0.1.0",
477 |       "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
478 |       "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
479 |       "dev": true,
480 |       "engines": {
481 |         "node": ">=10"
482 |       },
483 |       "funding": {
484 |         "url": "https://github.com/sponsors/sindresorhus"
485 |       }
486 |     },
487 |     "node_modules/js-yaml": {
488 |       "version": "4.1.0",
489 |       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
490 |       "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
491 |       "dev": true,
492 |       "dependencies": {
493 |         "argparse": "^2.0.1"
494 |       },
495 |       "bin": {
496 |         "js-yaml": "bin/js-yaml.js"
497 |       }
498 |     },
499 |     "node_modules/locate-path": {
500 |       "version": "6.0.0",
501 |       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
502 |       "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
503 |       "dev": true,
504 |       "dependencies": {
505 |         "p-locate": "^5.0.0"
506 |       },
507 |       "engines": {
508 |         "node": ">=10"
509 |       },
510 |       "funding": {
511 |         "url": "https://github.com/sponsors/sindresorhus"
512 |       }
513 |     },
514 |     "node_modules/log-symbols": {
515 |       "version": "4.1.0",
516 |       "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
517 |       "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
518 |       "dev": true,
519 |       "dependencies": {
520 |         "chalk": "^4.1.0",
521 |         "is-unicode-supported": "^0.1.0"
522 |       },
523 |       "engines": {
524 |         "node": ">=10"
525 |       },
526 |       "funding": {
527 |         "url": "https://github.com/sponsors/sindresorhus"
528 |       }
529 |     },
530 |     "node_modules/minimatch": {
531 |       "version": "5.1.6",
532 |       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
533 |       "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
534 |       "dev": true,
535 |       "license": "ISC",
536 |       "dependencies": {
537 |         "brace-expansion": "^2.0.1"
538 |       },
539 |       "engines": {
540 |         "node": ">=10"
541 |       }
542 |     },
543 |     "node_modules/mocha": {
544 |       "version": "10.7.3",
545 |       "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz",
546 |       "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==",
547 |       "dev": true,
548 |       "license": "MIT",
549 |       "dependencies": {
550 |         "ansi-colors": "^4.1.3",
551 |         "browser-stdout": "^1.3.1",
552 |         "chokidar": "^3.5.3",
553 |         "debug": "^4.3.5",
554 |         "diff": "^5.2.0",
555 |         "escape-string-regexp": "^4.0.0",
556 |         "find-up": "^5.0.0",
557 |         "glob": "^8.1.0",
558 |         "he": "^1.2.0",
559 |         "js-yaml": "^4.1.0",
560 |         "log-symbols": "^4.1.0",
561 |         "minimatch": "^5.1.6",
562 |         "ms": "^2.1.3",
563 |         "serialize-javascript": "^6.0.2",
564 |         "strip-json-comments": "^3.1.1",
565 |         "supports-color": "^8.1.1",
566 |         "workerpool": "^6.5.1",
567 |         "yargs": "^16.2.0",
568 |         "yargs-parser": "^20.2.9",
569 |         "yargs-unparser": "^2.0.0"
570 |       },
571 |       "bin": {
572 |         "_mocha": "bin/_mocha",
573 |         "mocha": "bin/mocha.js"
574 |       },
575 |       "engines": {
576 |         "node": ">= 14.0.0"
577 |       }
578 |     },
579 |     "node_modules/ms": {
580 |       "version": "2.1.3",
581 |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
582 |       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
583 |       "dev": true
584 |     },
585 |     "node_modules/normalize-path": {
586 |       "version": "3.0.0",
587 |       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
588 |       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
589 |       "dev": true,
590 |       "engines": {
591 |         "node": ">=0.10.0"
592 |       }
593 |     },
594 |     "node_modules/once": {
595 |       "version": "1.4.0",
596 |       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
597 |       "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
598 |       "dev": true,
599 |       "dependencies": {
600 |         "wrappy": "1"
601 |       }
602 |     },
603 |     "node_modules/p-limit": {
604 |       "version": "3.1.0",
605 |       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
606 |       "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
607 |       "dev": true,
608 |       "dependencies": {
609 |         "yocto-queue": "^0.1.0"
610 |       },
611 |       "engines": {
612 |         "node": ">=10"
613 |       },
614 |       "funding": {
615 |         "url": "https://github.com/sponsors/sindresorhus"
616 |       }
617 |     },
618 |     "node_modules/p-locate": {
619 |       "version": "5.0.0",
620 |       "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
621 |       "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
622 |       "dev": true,
623 |       "dependencies": {
624 |         "p-limit": "^3.0.2"
625 |       },
626 |       "engines": {
627 |         "node": ">=10"
628 |       },
629 |       "funding": {
630 |         "url": "https://github.com/sponsors/sindresorhus"
631 |       }
632 |     },
633 |     "node_modules/path-exists": {
634 |       "version": "4.0.0",
635 |       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
636 |       "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
637 |       "dev": true,
638 |       "engines": {
639 |         "node": ">=8"
640 |       }
641 |     },
642 |     "node_modules/picomatch": {
643 |       "version": "2.3.1",
644 |       "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
645 |       "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
646 |       "dev": true,
647 |       "engines": {
648 |         "node": ">=8.6"
649 |       },
650 |       "funding": {
651 |         "url": "https://github.com/sponsors/jonschlinkert"
652 |       }
653 |     },
654 |     "node_modules/randombytes": {
655 |       "version": "2.1.0",
656 |       "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
657 |       "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
658 |       "dev": true,
659 |       "license": "MIT",
660 |       "dependencies": {
661 |         "safe-buffer": "^5.1.0"
662 |       }
663 |     },
664 |     "node_modules/readdirp": {
665 |       "version": "3.6.0",
666 |       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
667 |       "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
668 |       "dev": true,
669 |       "dependencies": {
670 |         "picomatch": "^2.2.1"
671 |       },
672 |       "engines": {
673 |         "node": ">=8.10.0"
674 |       }
675 |     },
676 |     "node_modules/require-directory": {
677 |       "version": "2.1.1",
678 |       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
679 |       "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
680 |       "dev": true,
681 |       "engines": {
682 |         "node": ">=0.10.0"
683 |       }
684 |     },
685 |     "node_modules/safe-buffer": {
686 |       "version": "5.2.1",
687 |       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
688 |       "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
689 |       "dev": true,
690 |       "funding": [
691 |         {
692 |           "type": "github",
693 |           "url": "https://github.com/sponsors/feross"
694 |         },
695 |         {
696 |           "type": "patreon",
697 |           "url": "https://www.patreon.com/feross"
698 |         },
699 |         {
700 |           "type": "consulting",
701 |           "url": "https://feross.org/support"
702 |         }
703 |       ],
704 |       "license": "MIT"
705 |     },
706 |     "node_modules/serialize-javascript": {
707 |       "version": "6.0.2",
708 |       "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
709 |       "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
710 |       "dev": true,
711 |       "license": "BSD-3-Clause",
712 |       "dependencies": {
713 |         "randombytes": "^2.1.0"
714 |       }
715 |     },
716 |     "node_modules/should": {
717 |       "version": "13.2.3",
718 |       "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz",
719 |       "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==",
720 |       "dev": true,
721 |       "dependencies": {
722 |         "should-equal": "^2.0.0",
723 |         "should-format": "^3.0.3",
724 |         "should-type": "^1.4.0",
725 |         "should-type-adaptors": "^1.0.1",
726 |         "should-util": "^1.0.0"
727 |       }
728 |     },
729 |     "node_modules/should-equal": {
730 |       "version": "2.0.0",
731 |       "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz",
732 |       "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==",
733 |       "dev": true,
734 |       "dependencies": {
735 |         "should-type": "^1.4.0"
736 |       }
737 |     },
738 |     "node_modules/should-format": {
739 |       "version": "3.0.3",
740 |       "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz",
741 |       "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==",
742 |       "dev": true,
743 |       "dependencies": {
744 |         "should-type": "^1.3.0",
745 |         "should-type-adaptors": "^1.0.1"
746 |       }
747 |     },
748 |     "node_modules/should-type": {
749 |       "version": "1.4.0",
750 |       "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz",
751 |       "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==",
752 |       "dev": true
753 |     },
754 |     "node_modules/should-type-adaptors": {
755 |       "version": "1.1.0",
756 |       "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz",
757 |       "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==",
758 |       "dev": true,
759 |       "dependencies": {
760 |         "should-type": "^1.3.0",
761 |         "should-util": "^1.0.0"
762 |       }
763 |     },
764 |     "node_modules/should-util": {
765 |       "version": "1.0.1",
766 |       "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz",
767 |       "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==",
768 |       "dev": true
769 |     },
770 |     "node_modules/string-width": {
771 |       "version": "4.2.3",
772 |       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
773 |       "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
774 |       "dev": true,
775 |       "dependencies": {
776 |         "emoji-regex": "^8.0.0",
777 |         "is-fullwidth-code-point": "^3.0.0",
778 |         "strip-ansi": "^6.0.1"
779 |       },
780 |       "engines": {
781 |         "node": ">=8"
782 |       }
783 |     },
784 |     "node_modules/strip-ansi": {
785 |       "version": "6.0.1",
786 |       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
787 |       "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
788 |       "dev": true,
789 |       "dependencies": {
790 |         "ansi-regex": "^5.0.1"
791 |       },
792 |       "engines": {
793 |         "node": ">=8"
794 |       }
795 |     },
796 |     "node_modules/strip-json-comments": {
797 |       "version": "3.1.1",
798 |       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
799 |       "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
800 |       "dev": true,
801 |       "engines": {
802 |         "node": ">=8"
803 |       },
804 |       "funding": {
805 |         "url": "https://github.com/sponsors/sindresorhus"
806 |       }
807 |     },
808 |     "node_modules/supports-color": {
809 |       "version": "8.1.1",
810 |       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
811 |       "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
812 |       "dev": true,
813 |       "dependencies": {
814 |         "has-flag": "^4.0.0"
815 |       },
816 |       "engines": {
817 |         "node": ">=10"
818 |       },
819 |       "funding": {
820 |         "url": "https://github.com/chalk/supports-color?sponsor=1"
821 |       }
822 |     },
823 |     "node_modules/to-regex-range": {
824 |       "version": "5.0.1",
825 |       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
826 |       "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
827 |       "dev": true,
828 |       "license": "MIT",
829 |       "dependencies": {
830 |         "is-number": "^7.0.0"
831 |       },
832 |       "engines": {
833 |         "node": ">=8.0"
834 |       }
835 |     },
836 |     "node_modules/workerpool": {
837 |       "version": "6.5.1",
838 |       "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
839 |       "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
840 |       "dev": true,
841 |       "license": "Apache-2.0"
842 |     },
843 |     "node_modules/wrap-ansi": {
844 |       "version": "7.0.0",
845 |       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
846 |       "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
847 |       "dev": true,
848 |       "dependencies": {
849 |         "ansi-styles": "^4.0.0",
850 |         "string-width": "^4.1.0",
851 |         "strip-ansi": "^6.0.0"
852 |       },
853 |       "engines": {
854 |         "node": ">=10"
855 |       },
856 |       "funding": {
857 |         "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
858 |       }
859 |     },
860 |     "node_modules/wrappy": {
861 |       "version": "1.0.2",
862 |       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
863 |       "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
864 |       "dev": true
865 |     },
866 |     "node_modules/y18n": {
867 |       "version": "5.0.8",
868 |       "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
869 |       "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
870 |       "dev": true,
871 |       "engines": {
872 |         "node": ">=10"
873 |       }
874 |     },
875 |     "node_modules/yargs": {
876 |       "version": "16.2.0",
877 |       "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
878 |       "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
879 |       "dev": true,
880 |       "dependencies": {
881 |         "cliui": "^7.0.2",
882 |         "escalade": "^3.1.1",
883 |         "get-caller-file": "^2.0.5",
884 |         "require-directory": "^2.1.1",
885 |         "string-width": "^4.2.0",
886 |         "y18n": "^5.0.5",
887 |         "yargs-parser": "^20.2.2"
888 |       },
889 |       "engines": {
890 |         "node": ">=10"
891 |       }
892 |     },
893 |     "node_modules/yargs-parser": {
894 |       "version": "20.2.9",
895 |       "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
896 |       "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
897 |       "dev": true,
898 |       "license": "ISC",
899 |       "engines": {
900 |         "node": ">=10"
901 |       }
902 |     },
903 |     "node_modules/yargs-unparser": {
904 |       "version": "2.0.0",
905 |       "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
906 |       "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
907 |       "dev": true,
908 |       "dependencies": {
909 |         "camelcase": "^6.0.0",
910 |         "decamelize": "^4.0.0",
911 |         "flat": "^5.0.2",
912 |         "is-plain-obj": "^2.1.0"
913 |       },
914 |       "engines": {
915 |         "node": ">=10"
916 |       }
917 |     },
918 |     "node_modules/yocto-queue": {
919 |       "version": "0.1.0",
920 |       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
921 |       "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
922 |       "dev": true,
923 |       "engines": {
924 |         "node": ">=10"
925 |       },
926 |       "funding": {
927 |         "url": "https://github.com/sponsors/sindresorhus"
928 |       }
929 |     }
930 |   }
931 | }
932 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "aws4",
 3 |   "version": "1.13.2",
 4 |   "description": "Signs and prepares requests using AWS Signature Version 4",
 5 |   "author": "Michael Hart  (https://github.com/mhart)",
 6 |   "license": "MIT",
 7 |   "repository": "github:mhart/aws4",
 8 |   "main": "aws4.js",
 9 |   "files": [
10 |     "aws4.js",
11 |     "lru.js"
12 |   ],
13 |   "scripts": {
14 |     "test": "mocha ./test/fast.js -R list",
15 |     "integration": "node ./test/slow.js"
16 |   },
17 |   "devDependencies": {
18 |     "mocha": "^10.7.3",
19 |     "should": "^13.2.3"
20 |   }
21 | }
22 | 


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-key-duplicate/get-header-key-duplicate.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=c9d5ea9f3f72853aea855b47ea873832890dbdd183b4468f858259531a5138ea


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-key-duplicate/get-header-key-duplicate.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | my-header1:value2,value2,value1
6 | x-amz-date:20150830T123600Z
7 | 
8 | host;my-header1;x-amz-date
9 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-key-duplicate/get-header-key-duplicate.req:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value2
4 | My-Header1:value2
5 | My-Header1:value1
6 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-key-duplicate/get-header-key-duplicate.sreq:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value2
4 | My-Header1:value2
5 | My-Header1:value1
6 | X-Amz-Date:20150830T123600Z
7 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=c9d5ea9f3f72853aea855b47ea873832890dbdd183b4468f858259531a5138ea


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-key-duplicate/get-header-key-duplicate.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | dc7f04a3abfde8d472b0ab1a418b741b7c67174dad1551b4117b15527fbe966c


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-multiline/get-header-value-multiline.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=ba17b383a53190154eb5fa66a1b836cc297cc0a3d70a5d00705980573d8ff790


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-multiline/get-header-value-multiline.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | my-header1:value1,value2,value3
6 | x-amz-date:20150830T123600Z
7 | 
8 | host;my-header1;x-amz-date
9 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-multiline/get-header-value-multiline.req:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value1
4 |   value2
5 |      value3
6 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-multiline/get-header-value-multiline.sreq:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value1
4 |   value2
5 |      value3
6 | X-Amz-Date:20150830T123600Z
7 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=ba17b383a53190154eb5fa66a1b836cc297cc0a3d70a5d00705980573d8ff790


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-multiline/get-header-value-multiline.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | b7b6cbfd8a0430b78891e986784da2630c8a135a8595cec25b26ea94f926ee55


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-order/get-header-value-order.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=08c7e5a9acfcfeb3ab6b2185e75ce8b1deb5e634ec47601a50643f830c755c01


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-order/get-header-value-order.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | my-header1:value4,value1,value3,value2
6 | x-amz-date:20150830T123600Z
7 | 
8 | host;my-header1;x-amz-date
9 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-order/get-header-value-order.req:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value4
4 | My-Header1:value1
5 | My-Header1:value3
6 | My-Header1:value2
7 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-order/get-header-value-order.sreq:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value4
4 | My-Header1:value1
5 | My-Header1:value3
6 | My-Header1:value2
7 | X-Amz-Date:20150830T123600Z
8 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=08c7e5a9acfcfeb3ab6b2185e75ce8b1deb5e634ec47601a50643f830c755c01


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-order/get-header-value-order.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 31ce73cd3f3d9f66977ad3dd957dc47af14df92fcd8509f59b349e9137c58b86


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-trim/get-header-value-trim.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;my-header2;x-amz-date, Signature=acc3ed3afb60bb290fc8d2dd0098b9911fcaa05412b367055dee359757a9c736


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-trim/get-header-value-trim.creq:
--------------------------------------------------------------------------------
 1 | GET
 2 | /
 3 | 
 4 | host:example.amazonaws.com
 5 | my-header1:value1
 6 | my-header2:"a b c"
 7 | x-amz-date:20150830T123600Z
 8 | 
 9 | host;my-header1;my-header2;x-amz-date
10 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-trim/get-header-value-trim.req:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1: value1
4 | My-Header2: "a   b   c"
5 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-trim/get-header-value-trim.sreq:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1: value1
4 | My-Header2: "a   b   c"
5 | X-Amz-Date:20150830T123600Z
6 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;my-header2;x-amz-date, Signature=acc3ed3afb60bb290fc8d2dd0098b9911fcaa05412b367055dee359757a9c736


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-header-value-trim/get-header-value-trim.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | a726db9b0df21c14f559d0a978e563112acb1b9e05476f0a6a1c7d68f28605c7


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-unreserved/get-unreserved.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=07ef7494c76fa4850883e2b006601f940f8a34d404d0cfa977f52a65bbf5f24f


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-unreserved/get-unreserved.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-unreserved/get-unreserved.req:
--------------------------------------------------------------------------------
1 | GET /-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-unreserved/get-unreserved.sreq:
--------------------------------------------------------------------------------
1 | GET /-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=07ef7494c76fa4850883e2b006601f940f8a34d404d0cfa977f52a65bbf5f24f


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-unreserved/get-unreserved.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 6a968768eefaa713e2a6b16b589a8ea192661f098f37349f4e2c0082757446f9


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-utf8/get-utf8.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=8318018e0b0f223aa2bbf98705b62bb787dc9c0e678f255a891fd03141be5d85


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-utf8/get-utf8.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /%E1%88%B4
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-utf8/get-utf8.req:
--------------------------------------------------------------------------------
1 | GET /ሴ HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-utf8/get-utf8.sreq:
--------------------------------------------------------------------------------
1 | GET /ሴ HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=8318018e0b0f223aa2bbf98705b62bb787dc9c0e678f255a891fd03141be5d85


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-utf8/get-utf8.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 2a0a97d02205e45ce2e994789806b19270cfbbb0921b278ccf58f5249ac42102


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-empty-query-key/get-vanilla-empty-query-key.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=a67d582fa61cc504c4bae71f336f98b97f1ea3c7a6bfe1b6e45aec72011b9aeb


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-empty-query-key/get-vanilla-empty-query-key.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | Param1=value1
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-empty-query-key/get-vanilla-empty-query-key.req:
--------------------------------------------------------------------------------
1 | GET /?Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-empty-query-key/get-vanilla-empty-query-key.sreq:
--------------------------------------------------------------------------------
1 | GET /?Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=a67d582fa61cc504c4bae71f336f98b97f1ea3c7a6bfe1b6e45aec72011b9aeb


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-empty-query-key/get-vanilla-empty-query-key.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 1e24db194ed7d0eec2de28d7369675a243488e08526e8c1c73571282f7c517ab


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=b97d918cfa904a5beff61c982a1b6f458b799221646efd99d3219ec94cdf2500


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | Param1=value1&Param2=value2
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.req:
--------------------------------------------------------------------------------
1 | GET /?Param2=value2&Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.sreq:
--------------------------------------------------------------------------------
1 | GET /?Param2=value2&Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=b97d918cfa904a5beff61c982a1b6f458b799221646efd99d3219ec94cdf2500


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 816cd5b414d056048ba4f7c5386d6e0533120fb1fcfa93762cf0fc39e2cf19e0


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key/get-vanilla-query-order-key.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=eedbc4e291e521cf13422ffca22be7d2eb8146eecf653089df300a15b2382bd1


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key/get-vanilla-query-order-key.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | Param1=Value1&Param1=value2
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key/get-vanilla-query-order-key.req:
--------------------------------------------------------------------------------
1 | GET /?Param1=value2&Param1=Value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key/get-vanilla-query-order-key.sreq:
--------------------------------------------------------------------------------
1 | GET /?Param1=value2&Param1=Value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=eedbc4e291e521cf13422ffca22be7d2eb8146eecf653089df300a15b2382bd1


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-key/get-vanilla-query-order-key.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 704b4cef673542d84cdff252633f065e8daeba5f168b77116f8b1bcaf3d38f89


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-value/get-vanilla-query-order-value.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5772eed61e12b33fae39ee5e7012498b51d56abc0abb7c60486157bd471c4694


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-value/get-vanilla-query-order-value.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | Param1=value1&Param1=value2
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-value/get-vanilla-query-order-value.req:
--------------------------------------------------------------------------------
1 | GET /?Param1=value2&Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-value/get-vanilla-query-order-value.sreq:
--------------------------------------------------------------------------------
1 | GET /?Param1=value2&Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5772eed61e12b33fae39ee5e7012498b51d56abc0abb7c60486157bd471c4694


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-order-value/get-vanilla-query-order-value.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | c968629d70850097a2d8781c9bf7edcb988b04cac14cca9be4acc3595f884606


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-unreserved/get-vanilla-query-unreserved.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=9c3e54bfcdf0b19771a7f523ee5669cdf59bc7cc0884027167c21bb143a40197


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-unreserved/get-vanilla-query-unreserved.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | -._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-unreserved/get-vanilla-query-unreserved.req:
--------------------------------------------------------------------------------
1 | GET /?-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-unreserved/get-vanilla-query-unreserved.sreq:
--------------------------------------------------------------------------------
1 | GET /?-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=9c3e54bfcdf0b19771a7f523ee5669cdf59bc7cc0884027167c21bb143a40197


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query-unreserved/get-vanilla-query-unreserved.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | c30d4703d9f799439be92736156d47ccfb2d879ddf56f5befa6d1d6aab979177


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query/get-vanilla-query.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query/get-vanilla-query.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query/get-vanilla-query.req:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query/get-vanilla-query.sreq:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-query/get-vanilla-query.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | bb579772317eb040ac9ed261061d46c1f17a8133879d6129b6e1c25292927e63


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-utf8-query/get-vanilla-utf8-query.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=2cdec8eed098649ff3a119c94853b13c643bcf08f8b0a1d91e12c9027818dd04


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-utf8-query/get-vanilla-utf8-query.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | %E1%88%B4=bar
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-utf8-query/get-vanilla-utf8-query.req:
--------------------------------------------------------------------------------
1 | GET /?ሴ=bar HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-utf8-query/get-vanilla-utf8-query.sreq:
--------------------------------------------------------------------------------
1 | GET /?ሴ=bar HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=2cdec8eed098649ff3a119c94853b13c643bcf08f8b0a1d91e12c9027818dd04


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla-utf8-query/get-vanilla-utf8-query.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | eb30c5bed55734080471a834cc727ae56beb50e5f39d1bff6d0d38cb192a7073


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla/get-vanilla.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla/get-vanilla.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla/get-vanilla.req:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla/get-vanilla.sreq:
--------------------------------------------------------------------------------
1 | GET / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/get-vanilla/get-vanilla.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | bb579772317eb040ac9ed261061d46c1f17a8133879d6129b6e1c25292927e63


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative-relative/get-relative-relative.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative-relative/get-relative-relative.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative-relative/get-relative-relative.req:
--------------------------------------------------------------------------------
1 | GET /example1/example2/../.. HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative-relative/get-relative-relative.sreq:
--------------------------------------------------------------------------------
1 | GET /example1/example2/../.. HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative-relative/get-relative-relative.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | bb579772317eb040ac9ed261061d46c1f17a8133879d6129b6e1c25292927e63


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative/get-relative.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative/get-relative.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative/get-relative.req:
--------------------------------------------------------------------------------
1 | GET /example/.. HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative/get-relative.sreq:
--------------------------------------------------------------------------------
1 | GET /example/.. HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-relative/get-relative.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | bb579772317eb040ac9ed261061d46c1f17a8133879d6129b6e1c25292927e63


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-dot-slash/get-slash-dot-slash.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-dot-slash/get-slash-dot-slash.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-dot-slash/get-slash-dot-slash.req:
--------------------------------------------------------------------------------
1 | GET /./ HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-dot-slash/get-slash-dot-slash.sreq:
--------------------------------------------------------------------------------
1 | GET /./ HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-dot-slash/get-slash-dot-slash.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | bb579772317eb040ac9ed261061d46c1f17a8133879d6129b6e1c25292927e63


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-pointless-dot/get-slash-pointless-dot.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=ef75d96142cf21edca26f06005da7988e4f8dc83a165a80865db7089db637ec5


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-pointless-dot/get-slash-pointless-dot.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /example
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-pointless-dot/get-slash-pointless-dot.req:
--------------------------------------------------------------------------------
1 | GET /./example HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-pointless-dot/get-slash-pointless-dot.sreq:
--------------------------------------------------------------------------------
1 | GET /./example HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=ef75d96142cf21edca26f06005da7988e4f8dc83a165a80865db7089db637ec5


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash-pointless-dot/get-slash-pointless-dot.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 214d50c111a8edc4819da6a636336472c916b5240f51e9a51b5c3305180cf702


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash/get-slash.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash/get-slash.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash/get-slash.req:
--------------------------------------------------------------------------------
1 | GET // HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash/get-slash.sreq:
--------------------------------------------------------------------------------
1 | GET // HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slash/get-slash.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | bb579772317eb040ac9ed261061d46c1f17a8133879d6129b6e1c25292927e63


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slashes/get-slashes.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=9a624bd73a37c9a373b5312afbebe7a714a789de108f0bdfe846570885f57e84


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slashes/get-slashes.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /example/
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slashes/get-slashes.req:
--------------------------------------------------------------------------------
1 | GET //example// HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slashes/get-slashes.sreq:
--------------------------------------------------------------------------------
1 | GET //example// HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=9a624bd73a37c9a373b5312afbebe7a714a789de108f0bdfe846570885f57e84


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-slashes/get-slashes.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | cb96b4ac96d501f7c5c15bc6d67b3035061cfced4af6585ad927f7e6c985c015


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-space/get-space.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=652487583200325589f1fba4c7e578f72c47cb61beeca81406b39ddec1366741


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-space/get-space.creq:
--------------------------------------------------------------------------------
1 | GET
2 | /example%20space/
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-space/get-space.req:
--------------------------------------------------------------------------------
1 | GET /example space/ HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-space/get-space.sreq:
--------------------------------------------------------------------------------
1 | GET /example space/ HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=652487583200325589f1fba4c7e578f72c47cb61beeca81406b39ddec1366741


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/get-space/get-space.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 63ee75631ed7234ae61b5f736dfc7754cdccfedbff4b5128a915706ee9390d86


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/normalize-path/normalize-path.txt:
--------------------------------------------------------------------------------
1 | A note about signing requests to Amazon S3:
2 | 
3 | In exception to this, you do not normalize URI paths for requests to Amazon S3. For example, if you have a bucket with an object named my-object//example//photo.user, use that path. Normalizing the path to my-object/example/photo.user will cause the request to fail. For more information, see Task 1: Create a Canonical Request in the Amazon Simple Storage Service API Reference: http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html#canonical-request


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-case/post-header-key-case.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5da7c1a2acd57cee7505fc6676e4e544621c30862966e37dddb68e92efbe5d6b


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-case/post-header-key-case.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-case/post-header-key-case.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-case/post-header-key-case.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5da7c1a2acd57cee7505fc6676e4e544621c30862966e37dddb68e92efbe5d6b


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-case/post-header-key-case.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 553f88c9e4d10fc9e109e2aeb65f030801b70c2f6468faca261d401ae622fc87


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-sort/post-header-key-sort.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=c5410059b04c1ee005303aed430f6e6645f61f4dc9e1461ec8f8916fdf18852c


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-sort/post-header-key-sort.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | host:example.amazonaws.com
5 | my-header1:value1
6 | x-amz-date:20150830T123600Z
7 | 
8 | host;my-header1;x-amz-date
9 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-sort/post-header-key-sort.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value1
4 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-sort/post-header-key-sort.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:value1
4 | X-Amz-Date:20150830T123600Z
5 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=c5410059b04c1ee005303aed430f6e6645f61f4dc9e1461ec8f8916fdf18852c


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-key-sort/post-header-key-sort.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 9368318c2967cf6de74404b30c65a91e8f6253e0a8659d6d5319f1a812f87d65


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-value-case/post-header-value-case.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=cdbc9802e29d2942e5e10b5bccfdd67c5f22c7c4e8ae67b53629efa58b974b7d


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-value-case/post-header-value-case.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | host:example.amazonaws.com
5 | my-header1:VALUE1
6 | x-amz-date:20150830T123600Z
7 | 
8 | host;my-header1;x-amz-date
9 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-value-case/post-header-value-case.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:VALUE1
4 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-value-case/post-header-value-case.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | My-Header1:VALUE1
4 | X-Amz-Date:20150830T123600Z
5 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;my-header1;x-amz-date, Signature=cdbc9802e29d2942e5e10b5bccfdd67c5f22c7c4e8ae67b53629efa58b974b7d


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-header-value-case/post-header-value-case.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | d51ced243e649e3de6ef63afbbdcbca03131a21a7103a1583706a64618606a93


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-after/post-sts-header-after.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5da7c1a2acd57cee7505fc6676e4e544621c30862966e37dddb68e92efbe5d6b


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-after/post-sts-header-after.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-after/post-sts-header-after.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-after/post-sts-header-after.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | X-Amz-Security-Token:AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
5 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5da7c1a2acd57cee7505fc6676e4e544621c30862966e37dddb68e92efbe5d6b


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-after/post-sts-header-after.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 553f88c9e4d10fc9e109e2aeb65f030801b70c2f6468faca261d401ae622fc87


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-before/post-sts-header-before.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=85d96828115b5dc0cfc3bd16ad9e210dd772bbebba041836c64533a82be05ead


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-before/post-sts-header-before.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | x-amz-security-token:AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
7 | 
8 | host;x-amz-date;x-amz-security-token
9 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-before/post-sts-header-before.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | X-Amz-Security-Token:AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-before/post-sts-header-before.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | X-Amz-Security-Token:AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
5 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=85d96828115b5dc0cfc3bd16ad9e210dd772bbebba041836c64533a82be05ead


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/post-sts-header-before/post-sts-header-before.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | c237e1b440d4c63c32ca95b5b99481081cb7b13c7e40434868e71567c1a882f6


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-sts-token/readme.txt:
--------------------------------------------------------------------------------
 1 | A note about using temporary security credentials:
 2 | 
 3 | You can use temporary security credentials provided by the AWS Security Token Service (AWS STS) to sign a request. The process is the same as using long-term credentials but requires an additional HTTP header or query string parameter for the security token. The name of the header or query string parameter is X-Amz-Security-Token, and the value is the session token (the string that you received from AWS STS when you obtained temporary security credentials).
 4 | 
 5 | When you add X-Amz-Security-Token, some services require that you include this parameter in the canonical (signed) request. For other services, you add this parameter at the end, after you calculate the signature. For details see the API reference documentation for that service.
 6 | 
 7 | The test suite has 2 examples:
 8 | 
 9 | post-sts-header-before - The X-Amz-Security-Token header is part of the canonical request.
10 | 
11 | post-sts-header-after - The X-Amz-Security-Token header is added to the request after you calculate the signature.
12 | 
13 | The test suite uses this example value for X-Amz-Security-Token:
14 | 
15 | AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-empty-query-value/post-vanilla-empty-query-value.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=28038455d6de14eafc1f9222cf5aa6f1a96197d7deb8263271d420d138af7f11


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-empty-query-value/post-vanilla-empty-query-value.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | Param1=value1
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-empty-query-value/post-vanilla-empty-query-value.req:
--------------------------------------------------------------------------------
1 | POST /?Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-empty-query-value/post-vanilla-empty-query-value.sreq:
--------------------------------------------------------------------------------
1 | POST /?Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=28038455d6de14eafc1f9222cf5aa6f1a96197d7deb8263271d420d138af7f11


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-empty-query-value/post-vanilla-empty-query-value.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 9d659678c1756bb3113e2ce898845a0a79dbbc57b740555917687f1b3340fbbd


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-query/post-vanilla-query.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=28038455d6de14eafc1f9222cf5aa6f1a96197d7deb8263271d420d138af7f11


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-query/post-vanilla-query.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | Param1=value1
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-query/post-vanilla-query.req:
--------------------------------------------------------------------------------
1 | POST /?Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-query/post-vanilla-query.sreq:
--------------------------------------------------------------------------------
1 | POST /?Param1=value1 HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=28038455d6de14eafc1f9222cf5aa6f1a96197d7deb8263271d420d138af7f11


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla-query/post-vanilla-query.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 9d659678c1756bb3113e2ce898845a0a79dbbc57b740555917687f1b3340fbbd


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla/post-vanilla.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5da7c1a2acd57cee7505fc6676e4e544621c30862966e37dddb68e92efbe5d6b


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla/post-vanilla.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | host:example.amazonaws.com
5 | x-amz-date:20150830T123600Z
6 | 
7 | host;x-amz-date
8 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla/post-vanilla.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla/post-vanilla.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Host:example.amazonaws.com
3 | X-Amz-Date:20150830T123600Z
4 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5da7c1a2acd57cee7505fc6676e4e544621c30862966e37dddb68e92efbe5d6b


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-vanilla/post-vanilla.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 553f88c9e4d10fc9e109e2aeb65f030801b70c2f6468faca261d401ae622fc87


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded-parameters/post-x-www-form-urlencoded-parameters.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=1a72ec8f64bd914b0e42e42607c7fbce7fb2c7465f63e3092b3b0d39fa77a6fe


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded-parameters/post-x-www-form-urlencoded-parameters.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | content-type:application/x-www-form-urlencoded; charset=utf8
5 | host:example.amazonaws.com
6 | x-amz-date:20150830T123600Z
7 | 
8 | content-type;host;x-amz-date
9 | 9095672bbd1f56dfc5b65f3e153adc8731a4a654192329106275f4c7b24d0b6e


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded-parameters/post-x-www-form-urlencoded-parameters.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Content-Type:application/x-www-form-urlencoded; charset=utf8
3 | Host:example.amazonaws.com
4 | X-Amz-Date:20150830T123600Z
5 | 
6 | Param1=value1


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded-parameters/post-x-www-form-urlencoded-parameters.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Content-Type:application/x-www-form-urlencoded; charset=utf8
3 | Host:example.amazonaws.com
4 | X-Amz-Date:20150830T123600Z
5 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=1a72ec8f64bd914b0e42e42607c7fbce7fb2c7465f63e3092b3b0d39fa77a6fe
6 | 
7 | Param1=value1


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded-parameters/post-x-www-form-urlencoded-parameters.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 2e1cf7ed91881a30569e46552437e4156c823447bf1781b921b5d486c568dd1c


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded/post-x-www-form-urlencoded.authz:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=ff11897932ad3f4e8b18135d722051e5ac45fc38421b1da7b9d196a0fe09473a


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded/post-x-www-form-urlencoded.creq:
--------------------------------------------------------------------------------
1 | POST
2 | /
3 | 
4 | content-type:application/x-www-form-urlencoded
5 | host:example.amazonaws.com
6 | x-amz-date:20150830T123600Z
7 | 
8 | content-type;host;x-amz-date
9 | 9095672bbd1f56dfc5b65f3e153adc8731a4a654192329106275f4c7b24d0b6e


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded/post-x-www-form-urlencoded.req:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Content-Type:application/x-www-form-urlencoded
3 | Host:example.amazonaws.com
4 | X-Amz-Date:20150830T123600Z
5 | 
6 | Param1=value1


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded/post-x-www-form-urlencoded.sreq:
--------------------------------------------------------------------------------
1 | POST / HTTP/1.1
2 | Content-Type:application/x-www-form-urlencoded
3 | Host:example.amazonaws.com
4 | X-Amz-Date:20150830T123600Z
5 | Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=ff11897932ad3f4e8b18135d722051e5ac45fc38421b1da7b9d196a0fe09473a
6 | 
7 | Param1=value1


--------------------------------------------------------------------------------
/test/aws-sig-v4-test-suite/post-x-www-form-urlencoded/post-x-www-form-urlencoded.sts:
--------------------------------------------------------------------------------
1 | AWS4-HMAC-SHA256
2 | 20150830T123600Z
3 | 20150830/us-east-1/service/aws4_request
4 | 42a5e5bb34198acb3e84da4f085bb7927f2bc277ca766e6d19c73c2154021281


--------------------------------------------------------------------------------
/test/fast.js:
--------------------------------------------------------------------------------
  1 | var fs = require('fs'),
  2 |     path = require('path'),
  3 |     should = require('should'),
  4 |     aws4 = require('../'),
  5 |     lru = require('../lru'),
  6 |     RequestSigner = aws4.RequestSigner,
  7 |     cred = {accessKeyId: 'ABCDEF', secretAccessKey: 'abcdef1234567890'},
  8 |     date = 'Wed, 26 Dec 2012 06:10:30 GMT',
  9 |     iso = '20121226T061030Z',
 10 |     auth = 'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/sqs/aws4_request, ' +
 11 |            'SignedHeaders=date;host;x-amz-date, ' +
 12 |            'Signature=d847efb54cd60f0a256174848f26e43af4b5168dbec3118dc9fd84e942285791'
 13 | 
 14 | describe('aws4', function() {
 15 | 
 16 |   before(function() {
 17 |     process.env.AWS_ACCESS_KEY_ID = cred.accessKeyId
 18 |     process.env.AWS_SECRET_ACCESS_KEY = cred.secretAccessKey
 19 |     delete process.env.AWS_SESSION_TOKEN
 20 |   })
 21 | 
 22 |   describe('#sign() when constructed with string url', function() {
 23 |     it('should parse into request correctly', function() {
 24 |       var signer = new RequestSigner('http://sqs.us-east-1.amazonaws.com/')
 25 |       signer.request.headers.Date = date
 26 |       signer.sign().headers.Authorization.should.equal(auth)
 27 |     })
 28 | 
 29 |     it('should also support elastic search', function() {
 30 |       var signer = new RequestSigner('https://search-cluster-name-aaaaaa0aa00aa0aaaaaaa00aaa.eu-west-1.es.amazonaws.com')
 31 |       signer.request.headers.Date = date
 32 |       signer.sign().headers.Authorization.should.equal('AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/eu-west-1/es/aws4_request, SignedHeaders=date;host;x-amz-date, Signature=2dba21885bd7ccb0c5775c578c18a5c81fd30db84d4a2911933152df01de5260')
 33 |     })
 34 |   })
 35 | 
 36 |   describe('RequestSigner', function() {
 37 |     it('should correctly recognise ses', function() {
 38 |       var signer = new RequestSigner('https://email.us-west-2.amazonaws.com')
 39 |       signer.service.should.equal('ses')
 40 |       signer.region.should.equal('us-west-2')
 41 |     })
 42 | 
 43 |     it('should correctly recognise es when interacting directly with the es api', function() {
 44 |       var signer = new RequestSigner('https://search-cluster-name-aaaaaa0aa00aa0aaaaaaa00aaa.eu-west-1.es.amazonaws.com')
 45 |       signer.service.should.equal('es')
 46 |       signer.region.should.equal('eu-west-1')
 47 |     })
 48 | 
 49 |     it('should correctly recognise es when interacting directly with aws\'s es configuration api', function() {
 50 |       var signer = new RequestSigner('https://es.us-west-2.amazonaws.com')
 51 |       signer.service.should.equal('es')
 52 |       signer.region.should.equal('us-west-2')
 53 |     })
 54 | 
 55 |     it('should correctly recognise sns', function() {
 56 |       var signer = new RequestSigner('https://sns.us-west-2.amazonaws.com')
 57 |       signer.service.should.equal('sns')
 58 |       signer.region.should.equal('us-west-2')
 59 |     })
 60 | 
 61 |     it('should know global endpoint is us-east-1 for sdb', function() {
 62 |       var signer = new RequestSigner('https://sdb.amazonaws.com')
 63 |       signer.service.should.equal('sdb')
 64 |       signer.region.should.equal('us-east-1')
 65 |     })
 66 | 
 67 |     it('should recognise older S3 bare url', function() {
 68 |       var signer = new RequestSigner('https://s3.amazonaws.com/jbarr-public/whatever')
 69 |       signer.service.should.equal('s3')
 70 |       signer.region.should.equal('us-east-1')
 71 |     })
 72 | 
 73 |     it('should recognise older S3 regional url', function() {
 74 |       var signer = new RequestSigner('https://s3.eu-west-3.amazonaws.com/jbarr-public/whatever')
 75 |       signer.service.should.equal('s3')
 76 |       signer.region.should.equal('eu-west-3')
 77 |     })
 78 | 
 79 |     it('should recognise super old S3 regional url', function() {
 80 |       var signer = new RequestSigner('https://s3-eu-west-1.amazonaws.com/jbarr-public/whatever')
 81 |       signer.service.should.equal('s3')
 82 |       signer.region.should.equal('eu-west-1')
 83 |     })
 84 | 
 85 |     it('should recognise newer S3 bare url', function() {
 86 |       var signer = new RequestSigner('https://jbarr-public.s3.amazonaws.com/whatever')
 87 |       signer.service.should.equal('s3')
 88 |       signer.region.should.equal('us-east-1')
 89 |     })
 90 | 
 91 |     it('should recognise newer S3 bare url', function() {
 92 |       var signer = new RequestSigner('https://jbarr-public.s3.amazonaws.com/whatever')
 93 |       signer.service.should.equal('s3')
 94 |       signer.region.should.equal('us-east-1')
 95 |     })
 96 | 
 97 |     it('should recognise newer S3 regional url', function() {
 98 |       var signer = new RequestSigner('https://jbarr-public.s3.eu-west-3.amazonaws.com/whatever')
 99 |       signer.service.should.equal('s3')
100 |       signer.region.should.equal('eu-west-3')
101 |     })
102 | 
103 |     it('should recognise newer, but kinda older, S3 regional url', function() {
104 |       var signer = new RequestSigner('https://jbarr-public.s3-eu-west-1.amazonaws.com/whatever')
105 |       signer.service.should.equal('s3')
106 |       signer.region.should.equal('eu-west-1')
107 |     })
108 | 
109 |     it('should not set extra headers for CodeCommit Git access', function() {
110 |       var signer = new RequestSigner({service: 'codecommit', method: 'GIT', host: 'example.com'})
111 |       signer.prepareRequest()
112 |       signer.request.headers.should.deepEqual({Host: 'example.com'})
113 |     })
114 | 
115 |     it('should not have a "Z" at end of timestamp for CodeCommit Git access', function() {
116 |       var signer = new RequestSigner({service: 'codecommit', method: 'GIT', host: 'example.com'})
117 |       signer.getDateTime().should.not.match(/Z$/)
118 |     })
119 | 
120 |     it('should not have a body hash in the canonical string for CodeCommit Git access', function() {
121 |       var signer = new RequestSigner({service: 'codecommit', method: 'GIT', host: 'example.com'})
122 |       signer.canonicalString().should.match(/\n$/)
123 |     })
124 |   })
125 | 
126 |   describe('#sign() with no credentials', function() {
127 |     it('should use process.env values', function() {
128 |       var opts = aws4.sign({service: 'sqs', headers: {Date: date}})
129 |       opts.headers.Authorization.should.equal(auth)
130 |     })
131 |   })
132 | 
133 |   describe('#sign() with credentials', function() {
134 |     it('should use passed in values', function() {
135 |       var cred = {accessKeyId: 'A', secretAccessKey: 'B'},
136 |           opts = aws4.sign({service: 'sqs', headers: {Date: date}}, cred)
137 |       opts.headers.Authorization.should.equal(
138 |         'AWS4-HMAC-SHA256 Credential=A/20121226/us-east-1/sqs/aws4_request, ' +
139 |         'SignedHeaders=date;host;x-amz-date, ' +
140 |         'Signature=5d8d587b6e3011935837d670e682646012977960d8a8d992503d852726af71b9')
141 |     })
142 |   })
143 | 
144 |   describe('#sign() with no host or region', function() {
145 |     it('should add hostname and default region', function() {
146 |       var opts = aws4.sign({service: 'sqs'})
147 |       opts.hostname.should.equal('sqs.us-east-1.amazonaws.com')
148 |       opts.headers.Host.should.equal('sqs.us-east-1.amazonaws.com')
149 |     })
150 | 
151 |     it('should add hostname and no region if service is regionless', function() {
152 |       var opts = aws4.sign({service: 'iam'})
153 |       opts.hostname.should.equal('iam.amazonaws.com')
154 |       opts.headers.Host.should.equal('iam.amazonaws.com')
155 |     })
156 | 
157 |     it('should add hostname and no region if s3 and us-east-1', function() {
158 |       var opts = aws4.sign({service: 's3'})
159 |       opts.hostname.should.equal('s3.amazonaws.com')
160 |       opts.headers.Host.should.equal('s3.amazonaws.com')
161 |     })
162 | 
163 |     it('should not add bucket to hostname if dot in s3 bucket and us-east-1', function() {
164 |       var opts = aws4.sign({service: 's3', path: '/jbarr.public'})
165 |       opts.hostname.should.equal('s3.amazonaws.com')
166 |       opts.headers.Host.should.equal('s3.amazonaws.com')
167 |     })
168 | 
169 |     it('should not add bucket to hostname if dot in s3 bucket and us-east-2', function() {
170 |       var opts = aws4.sign({service: 's3', region: 'us-east-2', path: '/jbarr.public/somefile'})
171 |       opts.hostname.should.equal('s3.us-east-2.amazonaws.com')
172 |       opts.headers.Host.should.equal('s3.us-east-2.amazonaws.com')
173 |     })
174 | 
175 |     it('should add hostname and no region if sdb and us-east-1', function() {
176 |       var opts = aws4.sign({service: 'sdb'})
177 |       opts.hostname.should.equal('sdb.amazonaws.com')
178 |       opts.headers.Host.should.equal('sdb.amazonaws.com')
179 |     })
180 | 
181 |     it('should populate AWS headers correctly', function() {
182 |       var opts = aws4.sign({service: 'sqs', headers: {Date: date}})
183 |       opts.headers['X-Amz-Date'].should.equal(iso)
184 |       opts.headers.Authorization.should.equal(auth)
185 |     })
186 |   })
187 | 
188 |   describe('#sign() with no host, but with region', function() {
189 |     it('should add correct hostname for regular services', function() {
190 |       var opts = aws4.sign({service: 'glacier', region: 'us-west-1'})
191 |       opts.hostname.should.equal('glacier.us-west-1.amazonaws.com')
192 |       opts.headers.Host.should.equal('glacier.us-west-1.amazonaws.com')
193 |     })
194 | 
195 |     it('should add correct hostname for s3', function() {
196 |       var opts = aws4.sign({service: 's3', region: 'us-west-1'})
197 |       opts.hostname.should.equal('s3.us-west-1.amazonaws.com')
198 |       opts.headers.Host.should.equal('s3.us-west-1.amazonaws.com')
199 |     })
200 | 
201 |     it('should add correct hostname for ses', function() {
202 |       var opts = aws4.sign({service: 'ses', region: 'us-west-1'})
203 |       opts.hostname.should.equal('email.us-west-1.amazonaws.com')
204 |       opts.headers.Host.should.equal('email.us-west-1.amazonaws.com')
205 |     })
206 |   })
207 | 
208 |   describe('#sign() with hostname', function() {
209 |     it('should populate AWS headers correctly', function() {
210 |       var opts = aws4.sign({hostname: 'sqs.us-east-1.amazonaws.com', headers: {Date: date}})
211 |       opts.headers['X-Amz-Date'].should.equal(iso)
212 |       opts.headers.Authorization.should.equal(auth)
213 |     })
214 | 
215 |     it('should use custom port correctly', function() {
216 |       var opts = aws4.sign({hostname: 'localhost', port: '9000', service: 's3', headers: {Date: date}})
217 |       opts.headers['X-Amz-Date'].should.equal(iso)
218 |       opts.headers.Authorization.should.equal(
219 |         'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/s3/aws4_request, ' +
220 |         'SignedHeaders=date;host;x-amz-content-sha256;x-amz-date, ' +
221 |         'Signature=6fda8a58c01edfcb6773c15ad5a276a893ce52978a8f5cd1705fae14df78cfd4')
222 |     })
223 |   })
224 | 
225 |   describe('#sign() with host', function() {
226 |     it('should populate AWS headers correctly', function() {
227 |       var opts = aws4.sign({host: 'sqs.us-east-1.amazonaws.com', headers: {Date: date}})
228 |       opts.headers['X-Amz-Date'].should.equal(iso)
229 |       opts.headers.Authorization.should.equal(auth)
230 |     })
231 | 
232 |     it('should use custom port correctly', function() {
233 |       var opts = aws4.sign({host: 'localhost', port: '9000', service: 's3', headers: {Date: date}})
234 |       opts.headers['X-Amz-Date'].should.equal(iso)
235 |       opts.headers.Authorization.should.equal(
236 |         'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/s3/aws4_request, ' +
237 |         'SignedHeaders=date;host;x-amz-content-sha256;x-amz-date, ' +
238 |         'Signature=6fda8a58c01edfcb6773c15ad5a276a893ce52978a8f5cd1705fae14df78cfd4')
239 |     })
240 |   })
241 | 
242 |   describe('#sign() with body', function() {
243 |     it('should use POST', function() {
244 |       var opts = aws4.sign({body: 'SomeAction'})
245 |       opts.method.should.equal('POST')
246 |     })
247 | 
248 |     it('should set Content-Type', function() {
249 |       var opts = aws4.sign({body: 'SomeAction'})
250 |       opts.headers['Content-Type'].should.equal('application/x-www-form-urlencoded; charset=utf-8')
251 |     })
252 |   })
253 | 
254 |   describe('#sign() with many different options', function() {
255 |     it('should populate AWS headers correctly', function() {
256 |       var opts = aws4.sign({
257 |         service: 'dynamodb',
258 |         region: 'ap-southeast-2',
259 |         method: 'DELETE',
260 |         path: '/Some/Path?param=key¶m=otherKey',
261 |         body: 'SomeAction=SomeThing&Whatever=SomeThingElse',
262 |         headers: {
263 |           Date: date,
264 |           'Content-Type': 'application/x-amz-json-1.0',
265 |           'X-Amz-Target': 'DynamoDB_20111205.ListTables',
266 |           'Connection': 'keep-alive',
267 |         },
268 |       })
269 |       opts.headers['X-Amz-Date'].should.equal(iso)
270 |       opts.headers.Authorization.should.equal(
271 |         'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/ap-southeast-2/dynamodb/aws4_request, ' +
272 |         'SignedHeaders=content-length;content-type;date;host;x-amz-date;x-amz-target, ' +
273 |         'Signature=f9a00417d284dfe2cfdef809652c1d54add4e159835a0c69ac8cbdaa227a5000')
274 |     })
275 |   })
276 | 
277 |   describe('#sign() with copies', function() {
278 |     it('should modify request/opts in place and return same object', function() {
279 |       var opts = {service: 'sqs'}
280 |       var newOpts = aws4.sign(opts)
281 |       opts.should.equal(newOpts)
282 |     })
283 | 
284 |     it('should not modify existing headers', function() {
285 |       var headers = {
286 |         'Content-Type': 'application/x-amz-json-1.0',
287 |         'X-Amz-Target': 'DynamoDB_20120810.ListTables',
288 |       }
289 |       var opts = aws4.sign({
290 |         service: 'dynamodb',
291 |         headers: headers,
292 |         body: '{}',
293 |       })
294 |       opts.headers.should.not.equal(headers)
295 |     })
296 |   })
297 | 
298 |   describe('#sign() with signQuery', function() {
299 |     it('should work with standard services', function() {
300 |       var opts = aws4.sign({
301 |         service: 'dynamodb',
302 |         path: '/?X-Amz-Date=' + iso,
303 |         headers: {
304 |           'Content-Type': 'application/x-amz-json-1.0',
305 |           'X-Amz-Target': 'DynamoDB_20120810.ListTables',
306 |         },
307 |         body: '{}',
308 |         signQuery: true,
309 |       })
310 |       opts.path.should.equal(
311 |         '/?X-Amz-Date=20121226T061030Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&' +
312 |         'X-Amz-Credential=ABCDEF%2F20121226%2Fus-east-1%2Fdynamodb%2Faws4_request&' +
313 |         'X-Amz-SignedHeaders=content-type%3Bhost%3Bx-amz-target&' +
314 |         'X-Amz-Signature=3529a3f866ef85935692c2f2f6e8edb67de2ec91ce79ba5f1dbe28fc66cb154e')
315 |     })
316 | 
317 |     it('should work with s3', function() {
318 |       var opts = aws4.sign({
319 |         service: 's3',
320 |         path: '/some-bucket?X-Amz-Date=' + iso,
321 |         signQuery: true,
322 |       })
323 |       opts.path.should.equal(
324 |         '/some-bucket?X-Amz-Date=20121226T061030Z&X-Amz-Expires=86400&X-Amz-Algorithm=AWS4-HMAC-SHA256&' +
325 |         'X-Amz-Credential=ABCDEF%2F20121226%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&' +
326 |         'X-Amz-Signature=1acb058aaf5ce6ea6125f03231ab2b64acc9ce05fd70e4c7f087515adc41814a')
327 |     })
328 | 
329 |     it('should adhere to RFC-3986', function() {
330 |       var opts = aws4.sign({
331 |         service: 's3',
332 |         path: '/some-bucket?a=!\'&b=()*&X-Amz-Date=' + iso,
333 |         signQuery: true,
334 |       })
335 |       opts.path.should.equal(
336 |         '/some-bucket?a=%21%27&b=%28%29%2A&X-Amz-Date=20121226T061030Z&X-Amz-Expires=86400&X-Amz-Algorithm=AWS4-HMAC-SHA256&' +
337 |         'X-Amz-Credential=ABCDEF%2F20121226%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&' +
338 |         'X-Amz-Signature=5f3e8e3406e27471183900f8ee891a6ae40e959c05394b4271a2b5b543d5a14a')
339 |     })
340 |   })
341 | 
342 |   describe('#sign() with X-Amz-Content-Sha256 header', function() {
343 |     it('should preserve given header', function() {
344 |       var opts = aws4.sign({
345 |         service: 's3',
346 |         method: 'PUT',
347 |         path: '/some-bucket/file.txt',
348 |         body: 'Test Body',
349 |         headers: {
350 |           'X-Amz-Content-Sha256': 'My-Generated-Body-Hash',
351 |         },
352 |       })
353 |       opts.headers['X-Amz-Content-Sha256'].should.equal('My-Generated-Body-Hash')
354 |     })
355 | 
356 |     it('should use given header in signature calculation', function() {
357 |       var opts = aws4.sign({
358 |         service: 's3',
359 |         method: 'PUT',
360 |         path: '/some-bucket/file.txt',
361 |         body: 'Test Body',
362 |         headers: {
363 |           Date: date,
364 |           'X-Amz-Content-Sha256': 'My-Generated-Body-Hash',
365 |         },
366 |       })
367 |       opts.headers.Authorization.should.equal(
368 |         'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/s3/aws4_request, ' +
369 |         'SignedHeaders=content-length;content-type;date;host;x-amz-content-sha256;x-amz-date, ' +
370 |         'Signature=afa4074a64185317be81ed18953c6df9ee3a63507e6711ad79a7534f4c0b0c54')
371 |     })
372 | 
373 |     it('should use given lowercase header in signature calculation', function() {
374 |       var opts = aws4.sign({
375 |         service: 's3',
376 |         method: 'PUT',
377 |         path: '/some-bucket/file.txt',
378 |         body: 'Test Body',
379 |         headers: {
380 |           Date: date,
381 |           'x-amz-content-sha256': 'My-Generated-Body-Hash',
382 |         },
383 |       })
384 |       opts.headers.Authorization.should.equal(
385 |         'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/s3/aws4_request, ' +
386 |         'SignedHeaders=content-length;content-type;date;host;x-amz-content-sha256;x-amz-date, ' +
387 |         'Signature=afa4074a64185317be81ed18953c6df9ee3a63507e6711ad79a7534f4c0b0c54')
388 |     })
389 |   })
390 | 
391 |   describe('#sign() with extraHeadersToIgnore', function() {
392 |     it('should generate signature correctly', function() {
393 |       var opts = aws4.sign({
394 |         host: '07tjusf2h91cunochc.us-east-1.aoss.amazonaws.com',
395 |         method: 'PUT',
396 |         path: '/my-index',
397 |         body: '{"mappings":{}}',
398 |         headers: {
399 |           Date: date,
400 |           'Content-Type': 'application/json',
401 |           'X-Amz-Content-Sha256': 'UNSIGNED-PAYLOAD',
402 |         },
403 |         extraHeadersToIgnore: {
404 |           'content-length': true
405 |         },
406 |       })
407 |       opts.headers.Authorization.should.equal(
408 |         'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/aoss/aws4_request, ' +
409 |         'SignedHeaders=content-type;date;host;x-amz-content-sha256;x-amz-date, ' +
410 |         'Signature=742b9db3c09dbc6d29dd965fa44ec2d004d4aed4f0f4d179d0ee989c08c9bf06')
411 |     })
412 |   })
413 | 
414 |   describe('#sign() with extraHeadersToInclude', function() {
415 |     it('should generate signature correctly', function() {
416 |       var opts = aws4.sign({
417 |         service: 'someservice',
418 |         path: '/whatever',
419 |         headers: {
420 |           Date: date,
421 |           'Range': 'bytes=200-1000, 2000-6576, 19000-',
422 |         },
423 |         extraHeadersToInclude: {
424 |           'range': true
425 |         },
426 |       })
427 |       opts.headers.Authorization.should.equal(
428 |         'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/someservice/aws4_request, ' +
429 |         'SignedHeaders=date;host;range;x-amz-date, ' +
430 |         'Signature=8298a63e47319d57c1af6dfb5e5e5f1b30d2515ad1130d7f240b57ce94302d59')
431 |     })
432 |   })
433 | 
434 |   describe('#signature() with CodeCommit Git access', function() {
435 |     it('should generate signature correctly', function() {
436 |       var signer = new RequestSigner({
437 |         service: 'codecommit',
438 |         host: 'git-codecommit.us-east-1.amazonaws.com',
439 |         method: 'GIT',
440 |         path: '/v1/repos/MyAwesomeRepo',
441 |       })
442 |       signer.request.headers.Date = date
443 |       signer.getDateTime().should.equal('20121226T061030')
444 |       delete signer.request.headers.Date
445 |       signer.signature().should.equal('2a9a182eb6afc3859ee590af942564b53b0c4e5beac2893052515401d06af92a')
446 |     })
447 |   })
448 | 
449 |   describe('#canonicalString()', function() {
450 |     it('should work with chars > 127 and < 255 with s3', function() {
451 |       var signer = new RequestSigner({service: 's3', path: '/ü'})
452 |       var canonical = signer.canonicalString().split('\n')
453 | 
454 |       canonical[1].should.equal('/%C3%BC')
455 |       canonical[2].should.equal('')
456 |       signer.sign().path.should.equal('/%C3%BC')
457 |     })
458 | 
459 |     it('should work with chars > 127 and < 255 with non-s3', function() {
460 |       var signer = new RequestSigner({service: 'es', path: '/ü'})
461 |       var canonical = signer.canonicalString().split('\n')
462 | 
463 |       canonical[1].should.equal('/%25C3%25BC')
464 |       canonical[2].should.equal('')
465 |       signer.sign().path.should.equal('/%C3%BC')
466 |     })
467 | 
468 |     it('should work with chars > 255 with s3', function() {
469 |       var signer = new RequestSigner({service: 's3', path: '/€'})
470 |       var canonical = signer.canonicalString().split('\n')
471 | 
472 |       canonical[1].should.equal('/%E2%82%AC')
473 |       canonical[2].should.equal('')
474 |       signer.sign().path.should.equal('/%E2%82%AC')
475 |     })
476 | 
477 |     it('should work with chars > 255 with non-s3', function() {
478 |       var signer = new RequestSigner({service: 'es', path: '/€'})
479 |       var canonical = signer.canonicalString().split('\n')
480 | 
481 |       canonical[1].should.equal('/%25E2%2582%25AC')
482 |       canonical[2].should.equal('')
483 |       signer.sign().path.should.equal('/%E2%82%AC')
484 |     })
485 | 
486 |     it('should work with chars > 255 with s3 and signQuery', function() {
487 |       var signer = new RequestSigner({service: 's3', path: '/€', signQuery: true})
488 |       var canonical = signer.canonicalString().split('\n')
489 | 
490 |       canonical[1].should.equal('/%E2%82%AC')
491 |       canonical[2].should.match(new RegExp('^X-Amz-Algorithm=AWS4-HMAC-SHA256&' +
492 |         'X-Amz-Credential=ABCDEF%2F\\d{8}%2Fus-east-1%2Fs3%2Faws4_request&' +
493 |         'X-Amz-Date=\\d{8}T\\d{6}Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host$'))
494 |     })
495 | 
496 |     it('should work with chars > 255 with non-s3 and signQuery', function() {
497 |       var signer = new RequestSigner({service: 'es', path: '/€', signQuery: true})
498 |       var canonical = signer.canonicalString().split('\n')
499 | 
500 |       canonical[1].should.equal('/%25E2%2582%25AC')
501 |       canonical[2].should.match(new RegExp('^X-Amz-Algorithm=AWS4-HMAC-SHA256&' +
502 |         'X-Amz-Credential=ABCDEF%2F\\d{8}%2Fus-east-1%2Fes%2Faws4_request&' +
503 |         'X-Amz-Date=\\d{8}T\\d{6}Z&X-Amz-SignedHeaders=host$'))
504 |     })
505 | 
506 |     it('should work with reserved chars with s3', function() {
507 |       var signer = new RequestSigner({service: 's3', path: '/%41'})
508 |       var canonical = signer.canonicalString().split('\n')
509 | 
510 |       canonical[1].should.equal('/A')
511 |       canonical[2].should.equal('')
512 |       signer.sign().path.should.equal('/%41')
513 |     })
514 | 
515 |     it('should work with reserved chars with non-s3', function() {
516 |       var signer = new RequestSigner({service: 'es', path: '/%41'})
517 |       var canonical = signer.canonicalString().split('\n')
518 | 
519 |       canonical[1].should.equal('/%2541')
520 |       canonical[2].should.equal('')
521 |       signer.sign().path.should.equal('/%41')
522 |     })
523 | 
524 |     it('should work with RFC-3986 chars with s3', function() {
525 |       var signer = new RequestSigner({service: 's3', path: '/!\'()*@%21%27%28%29%2A?a=A&*=a&@=b'})
526 |       var canonical = signer.canonicalString().split('\n')
527 | 
528 |       canonical[1].should.equal('/%21%27%28%29%2A%40%21%27%28%29%2A')
529 |       canonical[2].should.equal('%2A=a&%40=b&a=A')
530 |       signer.sign().path.should.equal('/!\'()*@%21%27%28%29%2A?a=A&%2A=a&%40=b')
531 |     })
532 | 
533 |     it('should work with RFC-3986 chars with non-s3', function() {
534 |       var signer = new RequestSigner({service: 'es', path: '/!\'()*@%21%27%28%29%2A?a=A&*=a&@=b'})
535 |       var canonical = signer.canonicalString().split('\n')
536 | 
537 |       canonical[1].should.equal('/%21%27%28%29%2A%40%2521%2527%2528%2529%252A')
538 |       canonical[2].should.equal('%2A=a&%40=b&a=A')
539 |       signer.sign().path.should.equal('/!\'()*@%21%27%28%29%2A?a=A&%2A=a&%40=b')
540 |     })
541 | 
542 |     it('should normalize casing on percent encoding with s3', function() {
543 |       var signer = new RequestSigner({service: 's3', path: '/%2a'})
544 |       var canonical = signer.canonicalString().split('\n')
545 | 
546 |       canonical[1].should.equal('/%2A')
547 |       canonical[2].should.equal('')
548 |       signer.sign().path.should.equal('/%2a')
549 |     })
550 | 
551 |     it('should just escape percent encoding on non-s3', function() {
552 |       var signer = new RequestSigner({service: 'es', path: '/%2a'})
553 |       var canonical = signer.canonicalString().split('\n')
554 | 
555 |       canonical[1].should.equal('/%252a')
556 |       canonical[2].should.equal('')
557 |       signer.sign().path.should.equal('/%2a')
558 |     })
559 | 
560 |     it('should decode %2F with s3', function() {
561 |       var signer = new RequestSigner({service: 's3', path: '/%2f%2f'})
562 |       var canonical = signer.canonicalString().split('\n')
563 | 
564 |       canonical[1].should.equal('///')
565 |       canonical[2].should.equal('')
566 |       signer.sign().path.should.equal('/%2f%2f')
567 |     })
568 | 
569 |     it('should just escape %2F on non-s3', function() {
570 |       var signer = new RequestSigner({service: 'es', path: '/%2f%2f'})
571 |       var canonical = signer.canonicalString().split('\n')
572 | 
573 |       canonical[1].should.equal('/%252f%252f')
574 |       canonical[2].should.equal('')
575 |       signer.sign().path.should.equal('/%2f%2f')
576 |     })
577 | 
578 |     it('should decode + as space with s3', function() {
579 |       var signer = new RequestSigner({service: 's3', path: '/++'})
580 |       var canonical = signer.canonicalString().split('\n')
581 | 
582 |       canonical[1].should.equal('/%20%20')
583 |       canonical[2].should.equal('')
584 |       signer.sign().path.should.equal('/++')
585 |     })
586 | 
587 |     it('should just leave + on non-s3', function() {
588 |       var signer = new RequestSigner({service: 'es', path: '/++'})
589 |       var canonical = signer.canonicalString().split('\n')
590 | 
591 |       canonical[1].should.equal('/%2B%2B')
592 |       canonical[2].should.equal('')
593 |       signer.sign().path.should.equal('/++')
594 |     })
595 | 
596 |     it('should decode %2B with s3', function() {
597 |       var signer = new RequestSigner({service: 's3', path: '/%2b%2b'})
598 |       var canonical = signer.canonicalString().split('\n')
599 | 
600 |       canonical[1].should.equal('/%2B%2B')
601 |       canonical[2].should.equal('')
602 |       signer.sign().path.should.equal('/%2b%2b')
603 |     })
604 | 
605 |     it('should just escape %2B on non-s3', function() {
606 |       var signer = new RequestSigner({service: 'es', path: '/%2b%2b'})
607 |       var canonical = signer.canonicalString().split('\n')
608 | 
609 |       canonical[1].should.equal('/%252b%252b')
610 |       canonical[2].should.equal('')
611 |       signer.sign().path.should.equal('/%2b%2b')
612 |     })
613 | 
614 |     it('should work with mixed chars > 127 and < 255 and percent encoding with s3', function() {
615 |       var signer = new RequestSigner({service: 's3', path: '/ü%41'})
616 |       var canonical = signer.canonicalString().split('\n')
617 | 
618 |       canonical[1].should.equal('/%C3%BCA')
619 |       canonical[2].should.equal('')
620 |       signer.sign().path.should.equal('/%C3%BCA')
621 |     })
622 | 
623 |     it('should work with mixed chars > 127 and < 255 percent encoding with non-s3', function() {
624 |       var signer = new RequestSigner({service: 'es', path: '/ü%41'})
625 |       var canonical = signer.canonicalString().split('\n')
626 | 
627 |       canonical[1].should.equal('/%25C3%25BCA')
628 |       canonical[2].should.equal('')
629 |       signer.sign().path.should.equal('/%C3%BCA')
630 |     })
631 | 
632 |     it('should work with mixed chars > 127 and < 255 and percent encoding and query params with s3', function() {
633 |       var signer = new RequestSigner({service: 's3', path: '/ü%41?a=%41ü'})
634 |       var canonical = signer.canonicalString().split('\n')
635 | 
636 |       canonical[1].should.equal('/%C3%BCA')
637 |       canonical[2].should.equal('a=A%C3%BC')
638 |       signer.sign().path.should.equal('/%C3%BCA?a=A%C3%BC')
639 |     })
640 | 
641 |     it('should work with mixed chars > 127 and < 255 percent encoding and query params with non-s3', function() {
642 |       var signer = new RequestSigner({service: 'es', path: '/ü%41?a=%41ü'})
643 |       var canonical = signer.canonicalString().split('\n')
644 | 
645 |       canonical[1].should.equal('/%25C3%25BCA')
646 |       canonical[2].should.equal('a=A%C3%BC')
647 |       signer.sign().path.should.equal('/%C3%BCA?a=A%C3%BC')
648 |     })
649 | 
650 |     it('should work with mixed chars > 255 and percent encoding and query params with s3', function() {
651 |       var signer = new RequestSigner({service: 's3', path: '/۟%41?۟=%41۟'})
652 |       var canonical = signer.canonicalString().split('\n')
653 | 
654 |       canonical[1].should.equal('/%E2%82%AC%C3%BCA')
655 |       canonical[2].should.equal('%E2%82%AC%C3%BC=A%E2%82%AC%C3%BC')
656 |       signer.sign().path.should.equal('/%E2%82%AC%C3%BCA?%E2%82%AC%C3%BC=A%E2%82%AC%C3%BC')
657 |     })
658 | 
659 |     it('should work with mixed chars > 255 percent encoding and query params with non-s3', function() {
660 |       var signer = new RequestSigner({service: 'es', path: '/۟%41?۟=%41۟'})
661 |       var canonical = signer.canonicalString().split('\n')
662 | 
663 |       canonical[1].should.equal('/%25E2%2582%25AC%25C3%25BCA')
664 |       canonical[2].should.equal('%E2%82%AC%C3%BC=A%E2%82%AC%C3%BC')
665 |       signer.sign().path.should.equal('/%E2%82%AC%C3%BCA?%E2%82%AC%C3%BC=A%E2%82%AC%C3%BC')
666 |     })
667 | 
668 |     it('should work with %2F in query params with s3', function() {
669 |       var signer = new RequestSigner({service: 's3', path: '/%2f?a=/&/=%2f'})
670 |       var canonical = signer.canonicalString().split('\n')
671 | 
672 |       canonical[1].should.equal('//')
673 |       canonical[2].should.equal('%2F=%2F&a=%2F')
674 |       signer.sign().path.should.equal('/%2f?a=%2F&%2F=%2F')
675 |     })
676 | 
677 |     it('should work with %2F in query params with non-s3', function() {
678 |       var signer = new RequestSigner({service: 'es', path: '/%2f?a=/&/=%2f'})
679 |       var canonical = signer.canonicalString().split('\n')
680 | 
681 |       canonical[1].should.equal('/%252f')
682 |       canonical[2].should.equal('%2F=%2F&a=%2F')
683 |       signer.sign().path.should.equal('/%2f?a=%2F&%2F=%2F')
684 |     })
685 | 
686 |     it('should work with query param order in s3', function() {
687 |       var signer = new RequestSigner({service: 's3', path: '/?a-=a&a=b&a=B&a=b&a=c'})
688 |       var canonical = signer.canonicalString().split('\n')
689 | 
690 |       canonical[1].should.equal('/')
691 |       canonical[2].should.equal('a=b&a-=a')
692 |       signer.sign().path.should.equal('/?a-=a&a=b&a=B&a=b&a=c')
693 |     })
694 | 
695 |     it('should work with query param order in non-s3', function() {
696 |       var signer = new RequestSigner({service: 'es', path: '/?a-=a&a=b&a=B&a=b&a=c'})
697 |       var canonical = signer.canonicalString().split('\n')
698 | 
699 |       canonical[1].should.equal('/')
700 |       canonical[2].should.equal('a=B&a=b&a=b&a=c&a-=a')
701 |       signer.sign().path.should.equal('/?a-=a&a=b&a=B&a=b&a=c')
702 |     })
703 | 
704 |     it('should not normalize path in s3', function() {
705 |       var signer = new RequestSigner({service: 's3', path: '//a/b/..//c/.?a=b'})
706 |       var canonical = signer.canonicalString().split('\n')
707 | 
708 |       canonical[1].should.equal('//a/b/..//c/.')
709 |       canonical[2].should.equal('a=b')
710 |       signer.sign().path.should.equal('//a/b/..//c/.?a=b')
711 |     })
712 | 
713 |     it('should normalize path in non-s3', function() {
714 |       var signer = new RequestSigner({service: 'es', path: '//a/b/..//c/.?a=b'})
715 |       var canonical = signer.canonicalString().split('\n')
716 | 
717 |       canonical[1].should.equal('/a/c')
718 |       canonical[2].should.equal('a=b')
719 |       signer.sign().path.should.equal('//a/b/..//c/.?a=b')
720 |     })
721 | 
722 |     it('should normalize path in non-s3 with slash on the end', function() {
723 |       var signer = new RequestSigner({service: 'es', path: '//a/b/..//c/./?a=b'})
724 |       var canonical = signer.canonicalString().split('\n')
725 | 
726 |       canonical[1].should.equal('/a/c/')
727 |       canonical[2].should.equal('a=b')
728 |       signer.sign().path.should.equal('//a/b/..//c/./?a=b')
729 |     })
730 | 
731 |     it('should deal with complex query params in s3', function() {
732 |       var signer = new RequestSigner({service: 's3', path: '/?&a=&&=&%41&'})
733 |       var canonical = signer.canonicalString().split('\n')
734 | 
735 |       canonical[1].should.equal('/')
736 |       canonical[2].should.equal('A=&a=')
737 |       signer.sign().path.should.equal('/?a=&A=')
738 |     })
739 | 
740 |     it('should deal with complex query params in non-s3', function() {
741 |       var signer = new RequestSigner({service: 'es', path: '/?&a=&&=&%41&'})
742 |       var canonical = signer.canonicalString().split('\n')
743 | 
744 |       canonical[1].should.equal('/')
745 |       canonical[2].should.equal('A=&a=')
746 |       signer.sign().path.should.equal('/?a=&A=')
747 |     })
748 | 
749 |     it('should deal with extraHeadersToIgnore', function() {
750 |       var signer = new RequestSigner({
751 |         host: '07tjusf2h91cunochc.us-east-1.aoss.amazonaws.com',
752 |         method: 'PUT',
753 |         path: '/my-index',
754 |         body: '{"mappings":{}}',
755 |         headers: {
756 |           Date: date,
757 |           'Content-Type': 'application/json',
758 |           'X-Amz-Content-Sha256': 'UNSIGNED-PAYLOAD',
759 |         },
760 |         extraHeadersToIgnore: {
761 |           'content-length': true
762 |         },
763 |       })
764 |       var canonical = signer.canonicalString().split('\n')
765 | 
766 |       canonical[3].should.equal('content-type:application/json')
767 |       canonical[4].should.equal('date:Wed, 26 Dec 2012 06:10:30 GMT')
768 |       canonical[5].should.equal('host:07tjusf2h91cunochc.us-east-1.aoss.amazonaws.com')
769 |       canonical[6].should.equal('x-amz-content-sha256:UNSIGNED-PAYLOAD')
770 |       canonical[7].should.equal('x-amz-date:20121226T061030Z')
771 |       canonical[8].should.equal('')
772 |       canonical[9].should.equal('content-type;date;host;x-amz-content-sha256;x-amz-date')
773 |     })
774 |   
775 |     it('should deal with extraHeadersToInclude', function() {
776 |       var signer = new RequestSigner({
777 |         service: 'someservice',
778 |         path: '/whatever',
779 |         headers: {
780 |           Date: date,
781 |           'Range': 'bytes=200-1000, 2000-6576, 19000-',
782 |         },
783 |         extraHeadersToInclude: {
784 |           'range': true
785 |         },
786 |       })
787 |       var canonical = signer.canonicalString().split('\n')
788 | 
789 |       canonical[3].should.equal('date:Wed, 26 Dec 2012 06:10:30 GMT')
790 |       canonical[4].should.equal('host:someservice.us-east-1.amazonaws.com')
791 |       canonical[5].should.equal('range:bytes=200-1000, 2000-6576, 19000-')
792 |       canonical[6].should.equal('x-amz-date:20121226T061030Z')
793 |       canonical[7].should.equal('')
794 |       canonical[8].should.equal('date;host;range;x-amz-date')
795 |     })
796 |   })
797 | 
798 |   describe('with AWS test suite', function() {
799 |     var CREDENTIALS = {
800 |       accessKeyId: 'AKIDEXAMPLE',
801 |       secretAccessKey: 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
802 |     }
803 |     var SERVICE = 'service'
804 |     var DATETIME = '20150830T123600Z'
805 | 
806 |     awsFixtures().forEach(function(test) {
807 | 
808 |       it('should pass ' + test.test, function() {
809 |         var signer = new RequestSigner({
810 |           service: SERVICE,
811 |           method: test.method,
812 |           host: test.host,
813 |           path: test.pathname,
814 |           headers: headerArrayToObject(test.headers),
815 |           body: test.body,
816 |           doNotModifyHeaders: true,
817 |           doNotEncodePath: true,
818 |         }, CREDENTIALS)
819 | 
820 |         if (signer.datetime == null) {
821 |           signer.datetime = DATETIME
822 |         }
823 | 
824 |         signer.canonicalString().should.equal(test.canonicalString)
825 |         signer.stringToSign().should.equal(test.stringToSign)
826 |         signer.sign().headers.Authorization.should.equal(test.authHeader)
827 |       })
828 | 
829 |     })
830 |   })
831 | })
832 | 
833 | 
834 | describe('lru', function() {
835 | 
836 |   it('should return nothing if does not exist yet', function() {
837 |     var cache = lru(5)
838 |     should.not.exist(cache.get('a'))
839 |   })
840 | 
841 |   it('should return value from single set', function() {
842 |     var cache = lru(5)
843 |     cache.set('a', 'A')
844 |     cache.get('a').should.equal('A')
845 |   })
846 | 
847 |   it('should return value if just at capacity', function() {
848 |     var cache = lru(5)
849 |     cache.set('a', 'A')
850 |     cache.set('b', 'B')
851 |     cache.set('c', 'C')
852 |     cache.set('d', 'D')
853 |     cache.set('e', 'E')
854 |     cache.get('e').should.equal('E')
855 |     cache.get('d').should.equal('D')
856 |     cache.get('c').should.equal('C')
857 |     cache.get('b').should.equal('B')
858 |     cache.get('a').should.equal('A')
859 |   })
860 | 
861 |   it('should not return value just over capacity', function() {
862 |     var cache = lru(5)
863 |     cache.set('a', 'A')
864 |     cache.set('b', 'B')
865 |     cache.set('c', 'C')
866 |     cache.set('d', 'D')
867 |     cache.set('e', 'E')
868 |     cache.set('f', 'F')
869 |     cache.get('f').should.equal('F')
870 |     cache.get('e').should.equal('E')
871 |     cache.get('d').should.equal('D')
872 |     cache.get('c').should.equal('C')
873 |     cache.get('b').should.equal('B')
874 |     should.not.exist(cache.get('a'))
875 |   })
876 | 
877 |   it('should return value if get recently', function() {
878 |     var cache = lru(5)
879 |     cache.set('a', 'A')
880 |     cache.set('b', 'B')
881 |     cache.set('c', 'C')
882 |     cache.set('d', 'D')
883 |     cache.set('e', 'E')
884 |     cache.get('a').should.equal('A')
885 |     cache.set('f', 'F')
886 |     cache.get('f').should.equal('F')
887 |     cache.get('e').should.equal('E')
888 |     cache.get('d').should.equal('D')
889 |     cache.get('c').should.equal('C')
890 |     cache.get('a').should.equal('A')
891 |     should.not.exist(cache.get('b'))
892 |   })
893 | 
894 |   it('should return value if set recently', function() {
895 |     var cache = lru(5)
896 |     cache.set('a', 'A')
897 |     cache.set('b', 'B')
898 |     cache.set('c', 'C')
899 |     cache.set('d', 'D')
900 |     cache.set('e', 'E')
901 |     cache.set('a', 'AA')
902 |     cache.set('f', 'F')
903 |     cache.get('f').should.equal('F')
904 |     cache.get('e').should.equal('E')
905 |     cache.get('d').should.equal('D')
906 |     cache.get('c').should.equal('C')
907 |     cache.get('a').should.equal('AA')
908 |     should.not.exist(cache.get('b'))
909 |   })
910 | 
911 | })
912 | 
913 | 
914 | function awsFixtures() {
915 |   return matchingFiles(path.join(__dirname, 'aws-sig-v4-test-suite'), /\.req$/).map(function(file) {
916 |     var test = file.split('/').pop().split('.')[0]
917 |     var filePieces = fs.readFileSync(file, 'utf8').trim().split('\n\n')
918 |     var preamble = filePieces[0]
919 |     var body = filePieces[1]
920 |     var lines = (preamble + '\n').split('\n')
921 |     var methodPath = lines[0].split(' ')
922 |     var method = methodPath[0]
923 |     var pathname = methodPath.slice(1, -1).join(' ')
924 |     var headerLines = lines.slice(1).join('\n').split(':')
925 |     var headers = []
926 |     var url = ''
927 |     var host = ''
928 |     for (var i = 0; i < headerLines.length - 1; i++) {
929 |       var name = headerLines[i]
930 |       var newlineIx = headerLines[i + 1].lastIndexOf('\n')
931 |       var value = headerLines[i + 1].slice(0, newlineIx)
932 |       headerLines[i + 1] = headerLines[i + 1].slice(newlineIx + 1)
933 |       if (name.toLowerCase() === 'host') {
934 |         host = value
935 |         url = 'https://' + value + pathname
936 |       } else {
937 |         value.split('\n').forEach(function(v) { headers.push([name, v]) })
938 |       }
939 |     }
940 |     var canonicalString = fs.readFileSync(file.replace(/\.req$/, '.creq'), 'utf8').trim()
941 |     var stringToSign = fs.readFileSync(file.replace(/\.req$/, '.sts'), 'utf8').trim()
942 |     var authHeader = fs.readFileSync(file.replace(/\.req$/, '.authz'), 'utf8').trim()
943 | 
944 |     return {
945 |       test: test,
946 |       method: method,
947 |       url: url,
948 |       host: host,
949 |       pathname: pathname,
950 |       headers: headers,
951 |       body: body,
952 |       canonicalString: canonicalString,
953 |       stringToSign: stringToSign,
954 |       authHeader: authHeader,
955 |     }
956 |   })
957 | }
958 | 
959 | function matchingFiles(dir, regex) {
960 |   var ls = fs.readdirSync(dir).map(function(file) { return path.join(dir, file) })
961 |   var dirs = ls.filter(function(file) { return fs.lstatSync(file).isDirectory() })
962 |   var files = ls.filter(regex.test.bind(regex))
963 |   dirs.forEach(function(dir) { files = files.concat(matchingFiles(dir, regex)) })
964 |   return files
965 | }
966 | 
967 | function headerArrayToObject(headersList) {
968 |   var headers = Object.create(null)
969 |   headersList.forEach(function(headerEntry) {
970 |     var headerName = headerEntry[0]
971 |     var headerValue = headerEntry[1].trim()
972 |     if (headers[headerName] != null) {
973 |       headers[headerName] += ',' + headerValue
974 |     } else {
975 |       headers[headerName] = headerValue
976 |     }
977 |   })
978 |   return headers
979 | }
980 | 


--------------------------------------------------------------------------------
/test/slow.js:
--------------------------------------------------------------------------------
  1 | const https = require('https')
  2 | const { RequestSigner } = require('../')
  3 | 
  4 | https.globalAgent.maxSockets = 10
  5 | 
  6 | void (async() => {
  7 |   let paths = [
  8 |     '/ü',
  9 |     '/€',
 10 |     '/%41',
 11 |     '/!\'()*@%21%27%28%29%2A',
 12 |     '/%2a',
 13 |     '/%2f%2f',
 14 |     '/ü%41',
 15 |     '/ü%41?a=%41ü',
 16 |     '/۟%41?۟=%41۟',
 17 |     '/%2f?a=/&/=%2f',
 18 |     '/?a=b&a=B&a=b&a=c',
 19 |     '//a/b/..//c/.?a=b',
 20 |     '//a/b/..//c/./?a=b',
 21 |     '/?&a=&&=&%41&',
 22 |     '/?a=A&*=a&@=b',
 23 |     '/?{~>)[=|\':\'_"&$*\'A+=a^~0$&A:{<$=/[<}>&^|<}/={^~|円&;^/( =({A-~&円/)円0=^*<:&){!|<=>[-(~',
 24 |     '/?{~>)[=|\':\'_"&$*\'A+=a^~0$&A:{<$=/[<}>&^|<}/={^~|&;^/( =({A-~&/)0=^*<:&){!|<=>[-(~',
 25 |     '/?s-=s-&s-=s&s',
 26 |     '/?s-{~>)[=|\':\'_"&s-{~>)[=a^~0$&s-{~>)[=A-~&円&s',
 27 |   ]
 28 | 
 29 |   let tests = [{
 30 |     url: 'https://runtime.sagemaker.us-east-1.amazonaws.com/a=b~ and c * \' (what+ever)!?a=b~ and c * \' @(whatever)!',
 31 |     method: 'POST',
 32 |     headers: {
 33 |       'Content-Type': 'application/x-amz-json-1.1',
 34 |       'Accept': 'application/json',
 35 |       'Accept-Encoding': 'gzip, deflate, br',
 36 |     },
 37 |     body: '{}',
 38 |   }, {
 39 |     url: 'https://runtime.sagemaker.us-east-1.amazonaws.com/a=b~ and c * \' (what+ever)!?a=b~ and c * \' @(whatever)!',
 40 |     signQuery: true,
 41 |     method: 'POST',
 42 |     headers: {
 43 |       'Content-Type': 'application/x-amz-json-1.1',
 44 |       'Accept': 'application/json',
 45 |       'Accept-Encoding': 'gzip, deflate, br',
 46 |       'X-Amz-Target': 'SageMaker.ListEndpoints',
 47 |     },
 48 |     body: '{}',
 49 |   }, {
 50 |     url: 'https://s3.amazonaws.com/test//`@$^&*()-_+[]{}\\|;:.,<>۟%41=b~ and c * \' //(whatever)!?۟`@$^&*()-_+[]{}\\|;:.,<>=`@$^&*()-_+[]{}\\|;:.,<>%41۟ab~ and c * \' (whatever)!',
 51 |     method: 'POST',
 52 |     body: '',
 53 |   }, {
 54 |     url: 'https://s3.amazonaws.com/test//`@$^&*()-_+[]{}\\|;:.,<>۟%41=b~ and c * \' //(whatever)!?۟`@$^&*()-_+[]{}\\|;:.,<>=`@$^&*()-_+[]{}\\|;:.,<>%41۟ab~ and c * \' (whatever)!',
 55 |     signQuery: true,
 56 |     method: 'POST',
 57 |     body: '',
 58 |   }]
 59 | 
 60 |   paths.forEach(p => tests.push({ url: `https://s3.amazonaws.com/test${p}` }))
 61 |   paths.forEach(p => tests.push({ url: `https://s3.amazonaws.com/test${p}`, signQuery: true }))
 62 |   paths.forEach(p => tests.push({ url: `https://runtime.sagemaker.us-east-1.amazonaws.com/test${p}` }))
 63 |   paths.forEach(p => tests.push({ url: `https://runtime.sagemaker.us-east-1.amazonaws.com/test${p}`, signQuery: true }))
 64 | 
 65 |   tests.forEach(test => {
 66 |     test.accessKeyId = process.env.AWS_ACCESS_KEY_ID
 67 |     test.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY
 68 |     test.sessionToken = process.env.AWS_SESSION_TOKEN
 69 |   })
 70 | 
 71 |   let okTests = [{
 72 |     url: 'https://s3.us-east-1.amazonaws.com/',
 73 |   }, {
 74 |     url: 'https://s3-eu-west-1.amazonaws.com/',
 75 |   }, {
 76 |     url: 'https://s3-us-east-2.amazonaws.com/',
 77 |   }, {
 78 |     url: 'https://sqs.us-east-1.amazonaws.com/?Action=ListQueues',
 79 |   }, {
 80 |     url: 'https://iam.amazonaws.com/?Action=ListGroups&Version=2010-05-08',
 81 |   }, {
 82 |     url: 'https://ec2.us-east-1.amazonaws.com/?Action=DescribeRegions&Version=2014-06-15',
 83 |   }, {
 84 |     url: 'https://sns.us-east-1.amazonaws.com/?Action=ListTopics&Version=2010-03-31',
 85 |   }, {
 86 |     url: 'https://sts.us-east-1.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15',
 87 |   }, {
 88 |     url: 'https://cloudsearch.us-east-1.amazonaws.com/?Action=ListDomainNames&Version=2013-01-01',
 89 |   }, {
 90 |     url: 'https://email.us-east-1.amazonaws.com/?Action=ListIdentities&Version=2010-12-01',
 91 |   }, {
 92 |     url: 'https://autoscaling.us-east-1.amazonaws.com/?Action=DescribeAutoScalingInstances&Version=2011-01-01',
 93 |   }, {
 94 |     url: 'https://elasticloadbalancing.us-east-1.amazonaws.com/?Action=DescribeLoadBalancers&Version=2012-06-01',
 95 |   }, {
 96 |     url: 'https://cloudformation.us-east-1.amazonaws.com/?Action=ListStacks&Version=2010-05-15',
 97 |   }, {
 98 |     url: 'https://elasticbeanstalk.us-east-1.amazonaws.com/?Action=ListAvailableSolutionStacks&Version=2010-12-01',
 99 |   }, {
100 |     url: 'https://rds.us-east-1.amazonaws.com/?Action=DescribeDBInstances&Version=2012-09-17',
101 |   }, {
102 |     url: 'https://monitoring.us-east-1.amazonaws.com/?Action=ListMetrics&Version=2010-08-01',
103 |   }, {
104 |     url: 'https://redshift.us-east-1.amazonaws.com/?Action=DescribeClusters&Version=2012-12-01',
105 |   }, {
106 |     url: 'https://cloudfront.amazonaws.com/2014-05-31/distribution',
107 |   }, {
108 |     url: 'https://elasticache.us-east-1.amazonaws.com/?Action=DescribeCacheClusters&Version=2014-07-15',
109 |   }, {
110 |     url: 'https://elasticmapreduce.us-east-1.amazonaws.com/?Action=ListClusters&Version=2009-03-31',
111 |   }, {
112 |     url: 'https://route53.amazonaws.com/2013-04-01/hostedzone',
113 |   }, {
114 |     url: 'https://cognito-sync.us-east-1.amazonaws.com/identitypools',
115 |   }, {
116 |     url: 'https://elastictranscoder.us-east-1.amazonaws.com/2012-09-25/pipelines',
117 |   }, {
118 |     url: 'https://lambda.us-east-1.amazonaws.com/2014-11-13/functions/',
119 |   }, {
120 |     url: 'https://ecs.us-east-1.amazonaws.com/?Action=ListClusters&Version=2014-11-13',
121 |   }, {
122 |     url: 'https://glacier.us-east-1.amazonaws.com/-/vaults',
123 |     headers: {
124 |       'X-Amz-Glacier-Version': '2012-06-01',
125 |       'Accept-Encoding': 'gzip, deflate, br',
126 |     },
127 |   }, {
128 |     url: 'https://dynamodb.us-east-1.amazonaws.com/',
129 |     headers: {
130 |       'Content-Type': 'application/x-amz-json-1.0',
131 |       'X-Amz-Target': 'DynamoDB_20120810.ListTables',
132 |       'Accept-Encoding': 'gzip, deflate, br',
133 |     },
134 |     body: '{}',
135 |   }, {
136 |     url: 'https://dynamodb.us-east-1.amazonaws.com/',
137 |     headers: {
138 |       'Content-Type': 'application/x-amz-json-1.0',
139 |       'X-Amz-Target': 'DynamoDB_20120810.ListTables',
140 |       'Accept-Encoding': 'gzip, deflate, br',
141 |       'User-Agent': 'node',
142 |     },
143 |     extraHeadersToInclude: {
144 |       'user-agent': true,
145 |     },
146 |     body: '{}',
147 |   }, {
148 |     url: 'https://dynamodb.us-east-1.amazonaws.com/',
149 |     headers: {
150 |       'Content-Type': 'application/x-amz-json-1.0',
151 |       'X-Amz-Target': 'DynamoDB_20120810.ListTables',
152 |       'Accept-Encoding': 'gzip, deflate, br',
153 |     },
154 |     extraHeadersToIgnore: {
155 |       'content-type': true,
156 |     },
157 |     body: '{}',
158 |   }, {
159 |     service: 'appstream',
160 |     url: 'https://appstream2.us-east-1.amazonaws.com/',
161 |     headers: {
162 |       'Content-Type': 'application/x-amz-json-1.1',
163 |       'X-Amz-Target': 'PhotonAdminProxyService.DescribeFleets',
164 |       'Accept-Encoding': 'gzip, deflate, br',
165 |     },
166 |     body: '{}',
167 |   }, {
168 |     url: 'https://storagegateway.us-east-1.amazonaws.com/',
169 |     headers: {
170 |       'Content-Type': 'application/x-amz-json-1.1',
171 |       'X-Amz-Target': 'StorageGateway_20120630.ListGateways',
172 |       'Accept-Encoding': 'gzip, deflate, br',
173 |     },
174 |     body: '{}',
175 |   }, {
176 |     url: 'https://datapipeline.us-east-1.amazonaws.com/',
177 |     headers: {
178 |       'Content-Type': 'application/x-amz-json-1.1',
179 |       'X-Amz-Target': 'DataPipeline.ListPipelines',
180 |       'Accept-Encoding': 'gzip, deflate, br',
181 |     },
182 |     body: '{}',
183 |   }, {
184 |     url: 'https://route53domains.us-east-1.amazonaws.com/',
185 |     headers: {
186 |       'Content-Type': 'application/x-amz-json-1.1',
187 |       'X-Amz-Target': 'Route53Domains_v20140515.ListDomains',
188 |       'Accept-Encoding': 'gzip, deflate, br',
189 |     },
190 |     body: '{}',
191 |   }, {
192 |     url: 'https://kinesis.us-east-1.amazonaws.com/',
193 |     headers: {
194 |       'Content-Type': 'application/x-amz-json-1.1',
195 |       'X-Amz-Target': 'Kinesis_20131202.ListStreams',
196 |       'Accept-Encoding': 'gzip, deflate, br',
197 |     },
198 |     body: '{}',
199 |   }, {
200 |     url: 'https://cloudtrail.us-east-1.amazonaws.com/',
201 |     headers: {
202 |       'Content-Type': 'application/x-amz-json-1.1',
203 |       'X-Amz-Target': 'CloudTrail_20131101.DescribeTrails',
204 |       'Accept-Encoding': 'gzip, deflate, br',
205 |     },
206 |     body: '{}',
207 |   }, {
208 |     url: 'https://logs.us-east-1.amazonaws.com/',
209 |     headers: {
210 |       'Content-Type': 'application/x-amz-json-1.1',
211 |       'X-Amz-Target': 'Logs_20140328.DescribeLogGroups',
212 |       'Accept-Encoding': 'gzip, deflate, br',
213 |     },
214 |     body: '{}',
215 |   }, {
216 |     url: 'https://codedeploy.us-east-1.amazonaws.com/',
217 |     headers: {
218 |       'Content-Type': 'application/x-amz-json-1.1',
219 |       'X-Amz-Target': 'CodeDeploy_20141006.ListApplications',
220 |       'Accept-Encoding': 'gzip, deflate, br',
221 |     },
222 |     body: '{}',
223 |   }, {
224 |     url: 'https://directconnect.us-east-1.amazonaws.com/',
225 |     headers: {
226 |       'Content-Type': 'application/x-amz-json-1.1',
227 |       'X-Amz-Target': 'OvertureService.DescribeConnections',
228 |       'Accept-Encoding': 'gzip, deflate, br',
229 |     },
230 |     body: '{}',
231 |   }, {
232 |     url: 'https://kms.us-east-1.amazonaws.com/',
233 |     headers: {
234 |       'Content-Type': 'application/x-amz-json-1.1',
235 |       'X-Amz-Target': 'TrentService.ListKeys',
236 |       'Accept-Encoding': 'gzip, deflate, br',
237 |     },
238 |     body: '{}',
239 |   }, {
240 |     url: 'https://config.us-east-1.amazonaws.com/',
241 |     headers: {
242 |       'Content-Type': 'application/x-amz-json-1.1',
243 |       'X-Amz-Target': 'StarlingDoveService.DescribeDeliveryChannels',
244 |       'Accept-Encoding': 'gzip, deflate, br',
245 |     },
246 |     body: '{}',
247 |   }, {
248 |     service: 'cloudhsm',
249 |     url: 'https://cloudhsmv2.us-east-1.amazonaws.com/',
250 |     headers: {
251 |       'Content-Type': 'application/x-amz-json-1.1',
252 |       'X-Amz-Target': 'BaldrApiService.DescribeClusters',
253 |       'Accept-Encoding': 'gzip, deflate, br',
254 |     },
255 |     body: '{}',
256 |   }, {
257 |     url: 'https://swf.us-east-1.amazonaws.com/',
258 |     headers: {
259 |       'Content-Type': 'application/x-amz-json-1.0',
260 |       'X-Amz-Target': 'SimpleWorkflowService.ListDomains',
261 |       'Accept-Encoding': 'gzip, deflate, br',
262 |     },
263 |     body: '{"registrationStatus":"REGISTERED"}',
264 |   }, {
265 |     url: 'https://cognito-identity.us-east-1.amazonaws.com/',
266 |     headers: {
267 |       'Content-Type': 'application/x-amz-json-1.1',
268 |       'X-Amz-Target': 'AWSCognitoIdentityService.ListIdentityPools',
269 |       'Accept-Encoding': 'gzip, deflate, br',
270 |     },
271 |     body: '{"MaxResults": 1}',
272 |   }]
273 | 
274 |   okTests = okTests.concat(okTests.map(test => Object.assign({ signQuery: true }, test)))
275 | 
276 |   okTests.forEach(test => {
277 |     test.accessKeyId = process.env.AWS_ACCESS_KEY_ID
278 |     test.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY
279 |     test.sessionToken = process.env.AWS_SESSION_TOKEN
280 |   })
281 | 
282 |   try {
283 |     const signed = await getSignedTests(tests)
284 |     const responses = await Promise.all(signed.map(request))
285 | 
286 |     responses.map((r, i) => {
287 |       if (/InvalidSignatureException|SignatureDoesNotMatch/.test(r.body)) {
288 |         return {
289 |           index: i,
290 |           method: signed[i].method || 'GET',
291 |           path: signed[i].path,
292 |           url: signed[i].url,
293 |           canonicalString: signed[i].canonicalString,
294 |           body: r.body.replace(/&/g, '&'),
295 |         }
296 |       } else {
297 |         console.log('Passed tests ' + i)
298 |       }
299 |     }).filter(Boolean).forEach(({ index, method, path, url, canonicalString, body }) => {
300 |       console.log('Test ' + index)
301 |       console.log(method + ' ' + path)
302 |       console.log('--------------')
303 |       console.log(url)
304 |       console.log('--------------')
305 |       console.log(canonicalString)
306 |       console.log('--------------')
307 |       console.log(body)
308 |       console.log('==============')
309 |     })
310 |   } catch (e) {
311 |     console.error(e)
312 |   }
313 | 
314 |   try {
315 |     const signed = await getSignedTests(okTests)
316 |     const responses = await Promise.all(signed.map(request))
317 | 
318 |     responses.map((r, i) => {
319 |       if (r.statusCode !== 200) {
320 |         return {
321 |           index: i,
322 |           method: signed[i].method || 'GET',
323 |           path: signed[i].path,
324 |           url: signed[i].url,
325 |           canonicalString: signed[i].canonicalString,
326 |           body: r.body.replace(/&/g, '&'),
327 |         }
328 |       } else {
329 |         console.log('Passed okTests ' + i)
330 |       }
331 |     }).filter(Boolean).forEach(({ index, method, path, url, canonicalString, body }) => {
332 |       console.log('Test ' + index)
333 |       console.log(method + ' ' + path)
334 |       console.log('--------------')
335 |       console.log(url)
336 |       console.log('--------------')
337 |       console.log(canonicalString)
338 |       console.log('--------------')
339 |       console.log(body)
340 |       console.log('==============')
341 |     })
342 |   } catch (e) {
343 |     console.error(e)
344 |   }
345 | })()
346 | 
347 | async function getSignedTests(tests) {
348 |   return tests.map(test => {
349 |     var url = test.url
350 |     var urlPieces = url.split('/')
351 |     test.host = urlPieces[2]
352 |     test.path = '/' + urlPieces.slice(3).join('/')
353 |     delete test.url
354 |     test.headers = Object.assign({}, test.headers)
355 |     var signer = new RequestSigner(test)
356 |     var signed = signer.sign()
357 |     signed.canonicalString = signer.canonicalString()
358 |     signed.url = url
359 |     return signed
360 |   })
361 | }
362 | 
363 | const RETRY_ERRS = ['EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'EMFILE']
364 | 
365 | async function request(options) {
366 |   options.retries = options.retries || 0
367 |   return new Promise((resolve, reject) => {
368 |     const onError = err => {
369 |       if (RETRY_ERRS.includes(err.code) && options.retries < 5) {
370 |         options.retries++
371 |         return request(options).then(resolve).catch(reject)
372 |       }
373 |       reject(err)
374 |     }
375 |     https.request(options, res => {
376 |       let bufs = []
377 |       res.on('error', onError)
378 |       res.on('data', bufs.push.bind(bufs))
379 |       res.on('end', () => {
380 |         resolve({
381 |           statusCode: res.statusCode,
382 |           headers: res.headers,
383 |           body: Buffer.concat(bufs).toString('utf8'),
384 |         })
385 |       })
386 |     }).on('error', onError).end(options.body)
387 |   })
388 | }
389 | 


--------------------------------------------------------------------------------