diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index f0fb0d37..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -ko_fi: richicoder diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3ce7a61..2a33c3fb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,124 +3,152 @@ on: branches: - master pull_request: + branches: + - master jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 with: node-version: '' - - name: setup npm cache + + - name: Setup NPM Cache uses: actions/cache@v1 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - - name: npm install + + - name: NPM Install run: npm ci - - name: npm build + + - name: NPM Build run: npm run build - - name: npm run test + + - name: NPM Run Test run: npm run test - integration: + integrationOSS: runs-on: ubuntu-latest - services: - vaultBasic: - image: vault:1.2.3 - ports: - - 8200/tcp - env: - VAULT_DEV_ROOT_TOKEN_ID: testtoken - options: --cap-add=IPC_LOCK - vaultEnterprise: - image: hashicorp/vault-enterprise:1.3.0_ent - ports: - - 8200/tcp - env: - VAULT_DEV_ROOT_TOKEN_ID: testtoken - options: --cap-add=IPC_LOCK + steps: + - uses: actions/checkout@v1 + + - name: Run docker-compose + run: docker-compose up -d vault + + - uses: actions/setup-node@v1 + with: + node-version: '' + + - name: Setup NPM Cache + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: NPM Install + run: npm ci + + - name: NPM Build + run: npm run build + + - name: NPM Run test;integration:basic + run: npm run test:integration:basic + env: + VAULT_HOST: localhost + VAULT_PORT: 8200 + CI: true + + integrationEnterprise: + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 - with: - node-version: '' - - name: setup npm cache - uses: actions/cache@v1 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - name: npm install - run: npm ci - - name: npm build - run: npm run build - - name: npm run test:integration:basic - run: npm run test:integration:basic - env: - VAULT_HOST: localhost - VAULT_PORT: ${{ job.services.vaultBasic.ports[8200] }} - CI: true - - name: npm run test:integration:enterprise - run: npm run test:integration:enterprise - env: - VAULT_HOST: localhost - VAULT_PORT: ${{ job.services.vaultEnterprise.ports[8200] }} - CI: true + - uses: actions/checkout@v1 + + - name: Run docker-compose + run: docker-compose up -d vault-enterprise + + - uses: actions/setup-node@v1 + with: + node-version: '' + + - name: Setup NPM Cache + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: NPM Install + run: npm ci + + - name: NPM Build + run: npm run build + + - name: NPM Run test:intergration:enterprise + run: npm run test:integration:enterprise + env: + VAULT_HOST: localhost + VAULT_PORT: 8200 + CI: true e2e: runs-on: ubuntu-latest - services: - vault: - image: vault:1.3.0 - ports: - - 8200/tcp - env: - VAULT_DEV_ROOT_TOKEN_ID: testtoken - options: --cap-add=IPC_LOCK - steps: - uses: actions/checkout@v1 + + - name: Run docker-compose + run: docker-compose up -d vault + - uses: actions/setup-node@v1 with: node-version: '' - - name: setup npm cache + + - name: Setup NPM Cache uses: actions/cache@v1 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - - name: npm install + + - name: NPM Install run: npm ci - - name: npm build + + - name: NPM Build run: npm run build - - name: setup vault + + - name: Setup Vault run: node ./integrationTests/e2e/setup.js env: VAULT_HOST: localhost - VAULT_PORT: ${{ job.services.vault.ports[8200] }} - - name: use vault action (default K/V version 2) + VAULT_PORT: 8200 + + - name: Test Vault Action (default KV V2) uses: ./ id: kv-secrets with: - url: http://localhost:${{ job.services.vault.ports[8200] }} + url: http://localhost:8200 token: testtoken secrets: | test secret ; test secret | NAMED_SECRET ; nested/test otherSecret ; - - name: use vault action (custom K/V version 1) + + - name: Test Vault Action (default KV V1) uses: ./ with: - url: http://localhost:${{ job.services.vault.ports[8200] }} + url: http://localhost:8200 token: testtoken path: my-secret kv-version: 1 @@ -128,19 +156,103 @@ jobs: test altSecret ; test altSecret | NAMED_ALTSECRET ; nested/test otherAltSecret ; - - name: use vault action (using cubbyhole engine) + + - name: Test Vault Action (cubbyhole) uses: ./ with: - url: http://localhost:${{ job.services.vault.ports[8200] }} + url: http://localhost:8200 token: testtoken secrets: | /cubbyhole/test foo ; /cubbyhole/test zip | NAMED_CUBBYSECRET ; - - name: verify + + - name: Verify Vault Action Outputs run: npm run test:e2e env: OTHER_SECRET_OUTPUT: ${{ steps.kv-secrets.outputs.otherSecret }} + e2e-tls: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Run docker-compose + run: docker-compose up -d vault-tls + + - uses: actions/setup-node@v1 + with: + node-version: '' + + - name: Setup NPM Cache + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: NPM Install + run: npm ci + + - name: NPM Build + run: npm run build + + - name: Setup Vault + run: node ./integrationTests/e2e-tls/setup.js + env: + VAULT_HOST: localhost + VAULT_PORT: 8200 + VAULTCA: ${{ secrets.VAULTCA }} + VAULT_CLIENT_CERT: ${{ secrets.VAULT_CLIENT_CERT }} + VAULT_CLIENT_KEY: ${{ secrets.VAULT_CLIENT_KEY }} + + - name: Test Vault Action (default KV V2) + uses: ./ + id: kv-secrets + with: + url: https://localhost:8200 + token: ${{ env.VAULT_TOKEN }} + caCertificate: ${{ secrets.VAULTCA }} + clientCertificate: ${{ secrets.VAULT_CLIENT_CERT }} + clientKey: ${{ secrets.VAULT_CLIENT_KEY }} + secrets: | + test secret ; + test secret | NAMED_SECRET ; + nested/test otherSecret ; + + - name: Test Vault Action (default KV V1) + uses: ./ + with: + url: https://localhost:8200 + token: ${{ env.VAULT_TOKEN }} + path: my-secret + kv-version: 1 + caCertificate: ${{ secrets.VAULTCA }} + clientCertificate: ${{ secrets.VAULT_CLIENT_CERT }} + clientKey: ${{ secrets.VAULT_CLIENT_KEY }} + secrets: | + test altSecret ; + test altSecret | NAMED_ALTSECRET ; + nested/test otherAltSecret ; + + - name: Test Vault Action (cubbyhole) + uses: ./ + with: + url: https://localhost:8200 + token: ${{ env.VAULT_TOKEN }} + secrets: | + /cubbyhole/test foo ; + /cubbyhole/test zip | NAMED_CUBBYSECRET ; + caCertificate: ${{ secrets.VAULTCA }} + clientCertificate: ${{ secrets.VAULT_CLIENT_CERT }} + clientKey: ${{ secrets.VAULT_CLIENT_KEY }} + + - name: Verify Vault Action Outputs + run: npm run test:e2e-tls + env: + OTHER_SECRET_OUTPUT: ${{ steps.kv-secrets.outputs.otherSecret }} + # Removing publish step for now. # publish: # if: github.event_name == 'push' && contains(github.ref, 'master') diff --git a/action.yml b/action.yml index bbb72812..652c6767 100644 --- a/action.yml +++ b/action.yml @@ -43,6 +43,19 @@ inputs: description: 'Whether or not export secrets as environment variables.' default: 'true' required: false + caCertificate: + description: 'Base64 encoded CA certificate to verify the Vault server certificate.' + required: false + clientCertificate: + description: 'Base64 encoded client certificate for mTLS communication with the Vault server.' + required: false + clientKey: + description: 'Base64 encoded client key for mTLS communication with the Vault server.' + required: false + tlsSkipVerify: + description: 'When set to true, disables verification of the Vault server certificate. Setting this to true in production is not recommended.' + required: false + default: "false" runs: using: 'node12' main: 'dist/index.js' diff --git a/dist/index.js b/dist/index.js index 2f0681e8..086c9d09 100644 --- a/dist/index.js +++ b/dist/index.js @@ -36,8 +36,6 @@ module.exports = /******/ // Load entry module and return exports /******/ return __webpack_require__(492); /******/ }; -/******/ // initialize runtime -/******/ runtime(__webpack_require__); /******/ /******/ // run startup /******/ return startup(); @@ -137,6 +135,38 @@ var eos = function(stream, opts, callback) { module.exports = eos; +/***/ }), + +/***/ 10: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const is_1 = __webpack_require__(534); +exports.default = (url) => { + // Cast to URL + url = url; + const options = { + protocol: url.protocol, + hostname: is_1.default.string(url.hostname) && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, + host: url.host, + hash: url.hash, + search: url.search, + pathname: url.pathname, + href: url.href, + path: `${url.pathname || ''}${url.search || ''}` + }; + if (is_1.default.string(url.port) && url.port.length !== 0) { + options.port = Number(url.port); + } + if (url.username || url.password) { + options.auth = `${url.username || ''}:${url.password || ''}`; + } + return options; +}; + + /***/ }), /***/ 11: @@ -180,67 +210,82 @@ function wrappy (fn, cb) { /***/ }), /***/ 16: -/***/ (function(module, __unusedexports, __webpack_require__) { - -"use strict"; - -const pump = __webpack_require__(453); -const bufferStream = __webpack_require__(375); +/***/ (function(module) { -class MaxBufferError extends Error { - constructor() { - super('maxBuffer exceeded'); - this.name = 'MaxBufferError'; - } -} +module.exports = require("tls"); -async function getStream(inputStream, options) { - if (!inputStream) { - return Promise.reject(new Error('Expected a stream')); - } +/***/ }), - options = { - maxBuffer: Infinity, - ...options - }; +/***/ 36: +/***/ (function(__unusedmodule, exports, __webpack_require__) { - const {maxBuffer} = options; +"use strict"; - let stream; - await new Promise((resolve, reject) => { - const rejectPromise = error => { - if (error) { // A null check - error.bufferedData = stream.getBufferedValue(); - } +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CancelError = exports.ParseError = void 0; +const p_cancelable_1 = __webpack_require__(557); +Object.defineProperty(exports, "CancelError", { enumerable: true, get: function () { return p_cancelable_1.CancelError; } }); +const core_1 = __webpack_require__(946); +class ParseError extends core_1.RequestError { + constructor(error, response) { + const { options } = response.request; + super(`${error.message} in "${options.url.toString()}"`, error, response.request); + this.name = 'ParseError'; + Object.defineProperty(this, 'response', { + enumerable: false, + value: response + }); + } +} +exports.ParseError = ParseError; +__exportStar(__webpack_require__(946), exports); - reject(error); - }; - stream = pump(inputStream, bufferStream(options), error => { - if (error) { - rejectPromise(error); - return; - } +/***/ }), - resolve(); - }); +/***/ 48: +/***/ (function(__unusedmodule, exports) { - stream.on('data', () => { - if (stream.getBufferedLength() > maxBuffer) { - rejectPromise(new MaxBufferError()); - } - }); - }); +"use strict"; - return stream.getBufferedValue(); +Object.defineProperty(exports, "__esModule", { value: true }); +class WeakableMap { + constructor() { + this.weakMap = new WeakMap(); + this.map = new Map(); + } + set(key, value) { + if (typeof key === 'object') { + this.weakMap.set(key, value); + } + else { + this.map.set(key, value); + } + } + get(key) { + if (typeof key === 'object') { + return this.weakMap.get(key); + } + return this.map.get(key); + } + has(key) { + if (typeof key === 'object') { + return this.weakMap.has(key); + } + return this.map.has(key); + } } - -module.exports = getStream; -// TODO: Remove this for the next major release -module.exports.default = getStream; -module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'}); -module.exports.array = (stream, options) => getStream(stream, {...options, array: true}); -module.exports.MaxBufferError = MaxBufferError; +exports.default = WeakableMap; /***/ }), @@ -302,6 +347,10 @@ function onceStrict (fn) { // TODO: Use the `URL` global when targeting Node.js 10 const URLParser = typeof URL === 'undefined' ? __webpack_require__(835).URL : URL; +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs +const DATA_URL_DEFAULT_MIME_TYPE = 'text/plain'; +const DATA_URL_DEFAULT_CHARSET = 'us-ascii'; + const testParameter = (name, filters) => { return filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name); }; @@ -327,17 +376,21 @@ const normalizeDataURL = (urlString, {stripHash}) => { // Lowercase MIME type const mimeType = (mediaType.shift() || '').toLowerCase(); const attributes = mediaType - .filter(Boolean) .map(attribute => { let [key, value = ''] = attribute.split('=').map(string => string.trim()); // Lowercase `charset` if (key === 'charset') { value = value.toLowerCase(); + + if (value === DATA_URL_DEFAULT_CHARSET) { + return ''; + } } return `${key}${value ? `=${value}` : ''}`; - }); + }) + .filter(Boolean); const normalizedMediaType = [ ...attributes @@ -347,7 +400,7 @@ const normalizeDataURL = (urlString, {stripHash}) => { normalizedMediaType.push('base64'); } - if (normalizedMediaType.length !== 0 || mimeType) { + if (normalizedMediaType.length !== 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) { normalizedMediaType.unshift(mimeType); } @@ -513,66 +566,6 @@ module.exports = normalizeUrl; module.exports.default = normalizeUrl; -/***/ }), - -/***/ 72: -/***/ (function(module, __unusedexports, __webpack_require__) { - -"use strict"; - -const {PassThrough: PassThroughStream} = __webpack_require__(413); - -module.exports = options => { - options = {...options}; - - const {array} = options; - let {encoding} = options; - const isBuffer = encoding === 'buffer'; - let objectMode = false; - - if (array) { - objectMode = !(encoding || isBuffer); - } else { - encoding = encoding || 'utf8'; - } - - if (isBuffer) { - encoding = null; - } - - const stream = new PassThroughStream({objectMode}); - - if (encoding) { - stream.setEncoding(encoding); - } - - let length = 0; - const chunks = []; - - stream.on('data', chunk => { - chunks.push(chunk); - - if (objectMode) { - length = chunks.length; - } else { - length += chunk.length; - } - }); - - stream.getBufferedValue = () => { - if (array) { - return chunks; - } - - return isBuffer ? Buffer.concat(chunks, length) : chunks.join(''); - }; - - stream.getBufferedLength = () => length; - - return stream; -}; - - /***/ }), /***/ 77: @@ -580,9 +573,16 @@ module.exports = options => { "use strict"; -function __export(m) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); +}; Object.defineProperty(exports, "__esModule", { value: true }); const url_1 = __webpack_require__(835); const create_1 = __webpack_require__(323); @@ -636,22 +636,24 @@ const defaults = { beforeError: [], afterResponse: [] }, + cache: undefined, + dnsCache: undefined, decompress: true, throwHttpErrors: true, followRedirect: true, isStream: false, - cache: false, - dnsCache: false, - useElectronNet: false, responseType: 'text', resolveBodyOnly: false, maxRedirects: 10, prefixUrl: '', methodRewriting: true, - allowGetBody: false, ignoreInvalidCookies: false, context: {}, - _pagination: { + // TODO: Set this to `true` when Got 12 gets released + http2: false, + allowGetBody: false, + https: undefined, + pagination: { transform: (response) => { if (response.request.options.responseType === 'json') { return response.body; @@ -682,8 +684,13 @@ const defaults = { }, filter: () => true, shouldContinue: () => true, - countLimit: Infinity - } + countLimit: Infinity, + backoff: 0, + requestLimit: 10000, + stackAllItems: true + }, + parseJson: (text) => JSON.parse(text), + stringifyJson: (object) => JSON.stringify(object) }, handlers: [create_1.defaultHandler], mutableDefaults: false @@ -693,21 +700,9 @@ exports.default = got; // For CommonJS default export support module.exports = got; module.exports.default = got; -// Export types -__export(__webpack_require__(839)); -var as_stream_1 = __webpack_require__(379); -exports.ResponseStream = as_stream_1.ProxyStream; -var errors_1 = __webpack_require__(378); -exports.GotError = errors_1.GotError; -exports.CacheError = errors_1.CacheError; -exports.RequestError = errors_1.RequestError; -exports.ReadError = errors_1.ReadError; -exports.ParseError = errors_1.ParseError; -exports.HTTPError = errors_1.HTTPError; -exports.MaxRedirectsError = errors_1.MaxRedirectsError; -exports.UnsupportedProtocolError = errors_1.UnsupportedProtocolError; -exports.TimeoutError = errors_1.TimeoutError; -exports.CancelError = errors_1.CancelError; +module.exports.__esModule = true; // Workaround for TS issue: https://github.com/sindresorhus/got/pull/1267 +__exportStar(__webpack_require__(323), exports); +__exportStar(__webpack_require__(577), exports); /***/ }), @@ -728,38 +723,32 @@ module.exports = require("os"); // We define these manually to ensure they're always copied // even if they would move up the prototype chain // https://nodejs.org/api/http.html#http_class_http_incomingmessage -const knownProperties = [ - 'aborted', - 'complete', +const knownProps = [ 'destroy', + 'setTimeout', + 'socket', 'headers', + 'trailers', + 'rawHeaders', + 'statusCode', 'httpVersion', 'httpVersionMinor', 'httpVersionMajor', - 'method', - 'rawHeaders', 'rawTrailers', - 'setTimeout', - 'socket', - 'statusCode', - 'statusMessage', - 'trailers', - 'url' + 'statusMessage' ]; module.exports = (fromStream, toStream) => { - const fromProperties = new Set(Object.keys(fromStream).concat(knownProperties)); + const fromProps = new Set(Object.keys(fromStream).concat(knownProps)); - for (const property of fromProperties) { - // Don't overwrite existing properties. - if (property in toStream) { + for (const prop of fromProps) { + // Don't overwrite existing properties + if (prop in toStream) { continue; } - toStream[property] = typeof fromStream[property] === 'function' ? fromStream[property].bind(fromStream) : fromStream[property]; + toStream[prop] = typeof fromStream[prop] === 'function' ? fromStream[prop].bind(fromStream) : fromStream[prop]; } - - return toStream; }; @@ -807,1561 +796,1281 @@ module.exports = Response; /***/ }), -/***/ 110: -/***/ (function(module, exports, __webpack_require__) { +/***/ 151: +/***/ (function(module, __unusedexports, __webpack_require__) { -"use strict"; -/* module decorator */ module = __webpack_require__.nmd(module); +// @ts-check +const core = __webpack_require__(470); -Object.defineProperty(exports, "__esModule", { value: true }); -const url_1 = __webpack_require__(835); -const util_1 = __webpack_require__(669); -const CacheableRequest = __webpack_require__(946); -const http = __webpack_require__(605); -const https = __webpack_require__(211); -const lowercaseKeys = __webpack_require__(474); -const toReadableStream = __webpack_require__(952); -const is_1 = __webpack_require__(534); -const cacheable_lookup_1 = __webpack_require__(753); -const errors_1 = __webpack_require__(378); -const known_hook_events_1 = __webpack_require__(766); -const dynamic_require_1 = __webpack_require__(415); -const get_body_size_1 = __webpack_require__(232); -const is_form_data_1 = __webpack_require__(219); -const merge_1 = __webpack_require__(164); -const options_to_url_1 = __webpack_require__(856); -const supports_brotli_1 = __webpack_require__(620); -const types_1 = __webpack_require__(839); -const nonEnumerableProperties = [ - 'context', - 'body', - 'json', - 'form' -]; -const isAgentByProtocol = (agent) => is_1.default.object(agent); -// TODO: `preNormalizeArguments` should merge `options` & `defaults` -exports.preNormalizeArguments = (options, defaults) => { - var _a, _b, _c, _d, _e, _f; - // `options.headers` - if (is_1.default.undefined(options.headers)) { - options.headers = {}; - } - else { - options.headers = lowercaseKeys(options.headers); - } - for (const [key, value] of Object.entries(options.headers)) { - if (is_1.default.null_(value)) { - throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`); - } - } - // `options.prefixUrl` - if (is_1.default.urlInstance(options.prefixUrl) || is_1.default.string(options.prefixUrl)) { - options.prefixUrl = options.prefixUrl.toString(); - if (options.prefixUrl.length !== 0 && !options.prefixUrl.endsWith('/')) { - options.prefixUrl += '/'; +/*** + * Authenticate with Vault and retrieve a Vault token that can be used for requests. + * @param {string} method + * @param {import('got').Got} client + */ +async function retrieveToken(method, client) { + switch (method) { + case 'approle': { + const vaultRoleId = core.getInput('roleId', { required: true }); + const vaultSecretId = core.getInput('secretId', { required: true }); + return await getClientToken(client, method, { role_id: vaultRoleId, secret_id: vaultSecretId }); } - } - else { - options.prefixUrl = defaults ? defaults.prefixUrl : ''; - } - // `options.hooks` - if (is_1.default.undefined(options.hooks)) { - options.hooks = {}; - } - if (is_1.default.object(options.hooks)) { - for (const event of known_hook_events_1.default) { - if (Reflect.has(options.hooks, event)) { - if (!is_1.default.array(options.hooks[event])) { - throw new TypeError(`Parameter \`${event}\` must be an Array, not ${is_1.default(options.hooks[event])}`); - } - } - else { - options.hooks[event] = []; - } + case 'github': { + const githubToken = core.getInput('githubToken', { required: true }); + return await getClientToken(client, method, { token: githubToken }); } - } - else { - throw new TypeError(`Parameter \`hooks\` must be an Object, not ${is_1.default(options.hooks)}`); - } - if (defaults) { - for (const event of known_hook_events_1.default) { - if (!(Reflect.has(options.hooks, event) && is_1.default.undefined(options.hooks[event]))) { - // @ts-ignore Union type array is not assignable to union array type - options.hooks[event] = [ - ...defaults.hooks[event], - ...options.hooks[event] - ]; - } - } - } - // `options.timeout` - if (is_1.default.number(options.timeout)) { - options.timeout = { request: options.timeout }; - } - else if (!is_1.default.object(options.timeout)) { - options.timeout = {}; - } - // `options.retry` - const { retry } = options; - if (defaults) { - options.retry = { ...defaults.retry }; - } - else { - options.retry = { - calculateDelay: retryObject => retryObject.computedValue, - limit: 0, - methods: [], - statusCodes: [], - errorCodes: [], - maxRetryAfter: undefined - }; - } - if (is_1.default.object(retry)) { - options.retry = { - ...options.retry, - ...retry - }; - } - else if (is_1.default.number(retry)) { - options.retry.limit = retry; - } - if (options.retry.maxRetryAfter === undefined) { - options.retry.maxRetryAfter = Math.min(...[options.timeout.request, options.timeout.connect].filter((n) => !is_1.default.nullOrUndefined(n))); - } - options.retry.methods = [...new Set(options.retry.methods.map(method => method.toUpperCase()))]; - options.retry.statusCodes = [...new Set(options.retry.statusCodes)]; - options.retry.errorCodes = [...new Set(options.retry.errorCodes)]; - // `options.dnsCache` - if (options.dnsCache && !(options.dnsCache instanceof cacheable_lookup_1.default)) { - options.dnsCache = new cacheable_lookup_1.default({ cacheAdapter: options.dnsCache }); - } - // `options.method` - if (is_1.default.string(options.method)) { - options.method = options.method.toUpperCase(); - } - else { - options.method = (_b = (_a = defaults) === null || _a === void 0 ? void 0 : _a.method, (_b !== null && _b !== void 0 ? _b : 'GET')); - } - // Better memory management, so we don't have to generate a new object every time - if (options.cache) { - options.cacheableRequest = new CacheableRequest( - // @ts-ignore Cannot properly type a function with multiple definitions yet - (requestOptions, handler) => requestOptions[types_1.requestSymbol](requestOptions, handler), options.cache); - } - // `options.cookieJar` - if (is_1.default.object(options.cookieJar)) { - let { setCookie, getCookieString } = options.cookieJar; - // Horrible `tough-cookie` check - if (setCookie.length === 4 && getCookieString.length === 0) { - if (!Reflect.has(setCookie, util_1.promisify.custom)) { - // @ts-ignore TS is dumb - it says `setCookie` is `never`. - setCookie = util_1.promisify(setCookie.bind(options.cookieJar)); - getCookieString = util_1.promisify(getCookieString.bind(options.cookieJar)); - } - } - else if (setCookie.length !== 2) { - throw new TypeError('`options.cookieJar.setCookie` needs to be an async function with 2 arguments'); - } - else if (getCookieString.length !== 1) { - throw new TypeError('`options.cookieJar.getCookieString` needs to be an async function with 1 argument'); - } - options.cookieJar = { setCookie, getCookieString }; - } - // `options.encoding` - if (is_1.default.null_(options.encoding)) { - throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead'); - } - // `options.maxRedirects` - if (!Reflect.has(options, 'maxRedirects') && !(defaults && Reflect.has(defaults, 'maxRedirects'))) { - options.maxRedirects = 0; - } - // Merge defaults - if (defaults) { - options = merge_1.default({}, defaults, options); - } - // `options._pagination` - if (is_1.default.object(options._pagination)) { - const { _pagination: pagination } = options; - if (!is_1.default.function_(pagination.transform)) { - throw new TypeError('`options._pagination.transform` must be implemented'); - } - if (!is_1.default.function_(pagination.shouldContinue)) { - throw new TypeError('`options._pagination.shouldContinue` must be implemented'); - } - if (!is_1.default.function_(pagination.filter)) { - throw new TypeError('`options._pagination.filter` must be implemented'); - } - if (!is_1.default.function_(pagination.paginate)) { - throw new TypeError('`options._pagination.paginate` must be implemented'); - } - } - // Other values - options.decompress = Boolean(options.decompress); - options.isStream = Boolean(options.isStream); - options.throwHttpErrors = Boolean(options.throwHttpErrors); - options.ignoreInvalidCookies = Boolean(options.ignoreInvalidCookies); - options.cache = (_c = options.cache, (_c !== null && _c !== void 0 ? _c : false)); - options.responseType = (_d = options.responseType, (_d !== null && _d !== void 0 ? _d : 'text')); - options.resolveBodyOnly = Boolean(options.resolveBodyOnly); - options.followRedirect = Boolean(options.followRedirect); - options.dnsCache = (_e = options.dnsCache, (_e !== null && _e !== void 0 ? _e : false)); - options.useElectronNet = Boolean(options.useElectronNet); - options.methodRewriting = Boolean(options.methodRewriting); - options.allowGetBody = Boolean(options.allowGetBody); - options.context = (_f = options.context, (_f !== null && _f !== void 0 ? _f : {})); - return options; -}; -exports.mergeOptions = (...sources) => { - let mergedOptions = exports.preNormalizeArguments({}); - // Non enumerable properties shall not be merged - const properties = {}; - for (const source of sources) { - mergedOptions = exports.preNormalizeArguments(merge_1.default({}, source), mergedOptions); - for (const name of nonEnumerableProperties) { - if (!Reflect.has(source, name)) { - continue; - } - properties[name] = { - writable: true, - configurable: true, - enumerable: false, - value: source[name] - }; - } - } - Object.defineProperties(mergedOptions, properties); - return mergedOptions; -}; -exports.normalizeArguments = (url, options, defaults) => { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; - // Merge options - if (typeof url === 'undefined') { - throw new TypeError('Missing `url` argument'); - } - const runInitHooks = (hooks, options) => { - if (hooks && options) { - for (const hook of hooks) { - const result = hook(options); - if (is_1.default.promise(result)) { - throw new TypeError('The `init` hook must be a synchronous function'); + default: { + if (!method || method === 'token') { + return core.getInput('token', { required: true }); + } else { + /** @type {string} */ + const payload = core.getInput('authPayload', { required: true }); + if (!payload) { + throw Error('When using a custom authentication method, you must provide the payload'); } + return await getClientToken(client, method, JSON.parse(payload.trim())); } } - }; - const hasUrl = is_1.default.urlInstance(url) || is_1.default.string(url); - if (hasUrl) { - if (options) { - if (Reflect.has(options, 'url')) { - throw new TypeError('The `url` option cannot be used if the input is a valid URL.'); - } - } - else { - options = {}; - } - // @ts-ignore URL is not URL - options.url = url; - runInitHooks((_a = defaults) === null || _a === void 0 ? void 0 : _a.options.hooks.init, options); - runInitHooks((_b = options.hooks) === null || _b === void 0 ? void 0 : _b.init, options); - } - else if (Reflect.has(url, 'resolve')) { - throw new Error('The legacy `url.Url` is deprecated. Use `URL` instead.'); - } - else { - runInitHooks((_c = defaults) === null || _c === void 0 ? void 0 : _c.options.hooks.init, url); - runInitHooks((_d = url.hooks) === null || _d === void 0 ? void 0 : _d.init, url); - if (options) { - runInitHooks((_e = defaults) === null || _e === void 0 ? void 0 : _e.options.hooks.init, options); - runInitHooks((_f = options.hooks) === null || _f === void 0 ? void 0 : _f.init, options); - } - } - if (hasUrl) { - options = exports.mergeOptions((_h = (_g = defaults) === null || _g === void 0 ? void 0 : _g.options, (_h !== null && _h !== void 0 ? _h : {})), (options !== null && options !== void 0 ? options : {})); - } - else { - options = exports.mergeOptions((_k = (_j = defaults) === null || _j === void 0 ? void 0 : _j.options, (_k !== null && _k !== void 0 ? _k : {})), url, (options !== null && options !== void 0 ? options : {})); - } - // Normalize URL - // TODO: drop `optionsToUrl` in Got 12 - if (is_1.default.string(options.url)) { - options.url = options.prefixUrl + options.url; - options.url = options.url.replace(/^unix:/, 'http://$&'); - if (options.searchParams || options.search) { - options.url = options.url.split('?')[0]; - } - // @ts-ignore URL is not URL - options.url = options_to_url_1.default({ - origin: options.url, - ...options - }); - } - else if (!is_1.default.urlInstance(options.url)) { - // @ts-ignore URL is not URL - options.url = options_to_url_1.default({ origin: options.prefixUrl, ...options }); - } - const normalizedOptions = options; - // Make it possible to change `options.prefixUrl` - let prefixUrl = options.prefixUrl; - Object.defineProperty(normalizedOptions, 'prefixUrl', { - set: (value) => { - if (!normalizedOptions.url.href.startsWith(value)) { - throw new Error(`Cannot change \`prefixUrl\` from ${prefixUrl} to ${value}: ${normalizedOptions.url.href}`); - } - normalizedOptions.url = new url_1.URL(value + normalizedOptions.url.href.slice(prefixUrl.length)); - prefixUrl = value; - }, - get: () => prefixUrl - }); - // Make it possible to remove default headers - for (const [key, value] of Object.entries(normalizedOptions.headers)) { - if (is_1.default.undefined(value)) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete normalizedOptions.headers[key]; - } - } - return normalizedOptions; -}; -const withoutBody = new Set(['HEAD']); -const withoutBodyUnlessSpecified = 'GET'; -exports.normalizeRequestArguments = async (options) => { - var _a, _b, _c; - options = exports.mergeOptions(options); - // Serialize body - const { headers } = options; - const hasNoContentType = is_1.default.undefined(headers['content-type']); - { - // TODO: these checks should be moved to `preNormalizeArguments` - const isForm = !is_1.default.undefined(options.form); - const isJson = !is_1.default.undefined(options.json); - const isBody = !is_1.default.undefined(options.body); - if ((isBody || isForm || isJson) && withoutBody.has(options.method)) { - throw new TypeError(`The \`${options.method}\` method cannot be used with a body`); - } - if (!options.allowGetBody && (isBody || isForm || isJson) && withoutBodyUnlessSpecified === options.method) { - throw new TypeError(`The \`${options.method}\` method cannot be used with a body`); - } - if ([isBody, isForm, isJson].filter(isTrue => isTrue).length > 1) { - throw new TypeError('The `body`, `json` and `form` options are mutually exclusive'); - } - if (isBody && - !is_1.default.nodeStream(options.body) && - !is_1.default.string(options.body) && - !is_1.default.buffer(options.body) && - !(is_1.default.object(options.body) && is_form_data_1.default(options.body))) { - throw new TypeError('The `body` option must be a stream.Readable, string or Buffer'); - } - if (isForm && !is_1.default.object(options.form)) { - throw new TypeError('The `form` option must be an Object'); - } - } - if (options.body) { - // Special case for https://github.com/form-data/form-data - if (is_1.default.object(options.body) && is_form_data_1.default(options.body) && hasNoContentType) { - headers['content-type'] = `multipart/form-data; boundary=${options.body.getBoundary()}`; - } - } - else if (options.form) { - if (hasNoContentType) { - headers['content-type'] = 'application/x-www-form-urlencoded'; - } - options.body = (new url_1.URLSearchParams(options.form)).toString(); - } - else if (options.json) { - if (hasNoContentType) { - headers['content-type'] = 'application/json'; - } - options.body = JSON.stringify(options.json); - } - const uploadBodySize = await get_body_size_1.default(options); - if (!is_1.default.nodeStream(options.body)) { - options.body = toReadableStream(options.body); - } - // See https://tools.ietf.org/html/rfc7230#section-3.3.2 - // A user agent SHOULD send a Content-Length in a request message when - // no Transfer-Encoding is sent and the request method defines a meaning - // for an enclosed payload body. For example, a Content-Length header - // field is normally sent in a POST request even when the value is 0 - // (indicating an empty payload body). A user agent SHOULD NOT send a - // Content-Length header field when the request message does not contain - // a payload body and the method semantics do not anticipate such a - // body. - if (is_1.default.undefined(headers['content-length']) && is_1.default.undefined(headers['transfer-encoding'])) { - if ((options.method === 'POST' || options.method === 'PUT' || options.method === 'PATCH' || options.method === 'DELETE' || (options.allowGetBody && options.method === 'GET')) && - !is_1.default.undefined(uploadBodySize)) { - // @ts-ignore We assign if it is undefined, so this IS correct - headers['content-length'] = String(uploadBodySize); - } - } - if (!options.isStream && options.responseType === 'json' && is_1.default.undefined(headers.accept)) { - headers.accept = 'application/json'; - } - if (options.decompress && is_1.default.undefined(headers['accept-encoding'])) { - headers['accept-encoding'] = supports_brotli_1.default ? 'gzip, deflate, br' : 'gzip, deflate'; - } - // Validate URL - if (options.url.protocol !== 'http:' && options.url.protocol !== 'https:') { - throw new errors_1.UnsupportedProtocolError(options); - } - decodeURI(options.url.toString()); - // Normalize request function - if (is_1.default.function_(options.request)) { - options[types_1.requestSymbol] = options.request; - delete options.request; - } - else { - options[types_1.requestSymbol] = options.url.protocol === 'https:' ? https.request : http.request; - } - // UNIX sockets - if (options.url.hostname === 'unix') { - const matches = /(?.+?):(?.+)/.exec(options.url.pathname); - if ((_a = matches) === null || _a === void 0 ? void 0 : _a.groups) { - const { socketPath, path } = matches.groups; - options = { - ...options, - socketPath, - path, - host: '' - }; - } - } - if (isAgentByProtocol(options.agent)) { - options.agent = (_b = options.agent[options.url.protocol.slice(0, -1)], (_b !== null && _b !== void 0 ? _b : options.agent)); - } - if (options.dnsCache) { - options.lookup = options.dnsCache.lookup; - } - /* istanbul ignore next: electron.net is broken */ - // No point in typing process.versions correctly, as - // `process.version.electron` is used only once, right here. - if (options.useElectronNet && process.versions.electron) { - const electron = dynamic_require_1.default(module, 'electron'); // Trick webpack - options.request = util_1.deprecate((_c = electron.net.request, (_c !== null && _c !== void 0 ? _c : electron.remote.net.request)), 'Electron support has been deprecated and will be removed in Got 11.\n' + - 'See https://github.com/sindresorhus/got/issues/899 for further information.', 'GOT_ELECTRON'); - } - // Got's `timeout` is an object, http's `timeout` is a number, so they're not compatible. - delete options.timeout; - // Set cookies - if (options.cookieJar) { - const cookieString = await options.cookieJar.getCookieString(options.url.toString()); - if (is_1.default.nonEmptyString(cookieString)) { - options.headers.cookie = cookieString; - } - else { - delete options.headers.cookie; - } } - // `http-cache-semantics` checks this - delete options.url; - return options; -}; - - -/***/ }), +} -/***/ 148: -/***/ (function(module, __unusedexports, __webpack_require__) { +/*** + * Call the appropriate login endpoint and parse out the token in the response. + * @param {import('got').Got} client + * @param {string} method + * @param {any} payload + */ +async function getClientToken(client, method, payload) { + /** @type {'json'} */ + const responseType = 'json'; + var options = { + json: payload, + responseType, + }; -"use strict"; + core.debug(`Retrieving Vault Token from v1/auth/${method}/login endpoint`); -const pTimeout = __webpack_require__(654); + /** @type {import('got').Response} */ + const response = await client.post(`v1/auth/${method}/login`, options); + if (response && response.body && response.body.auth && response.body.auth.client_token) { + core.debug('✔ Vault Token successfully retrieved'); -const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; + core.startGroup('Token Info'); + core.debug(`Operating under policies: ${JSON.stringify(response.body.auth.policies)}`); + core.debug(`Token Metadata: ${JSON.stringify(response.body.auth.metadata)}`); + core.endGroup(); -const normalizeEmitter = emitter => { - const addListener = emitter.on || emitter.addListener || emitter.addEventListener; - const removeListener = emitter.off || emitter.removeListener || emitter.removeEventListener; + return response.body.auth.client_token; + } else { + throw Error(`Unable to retrieve token from ${method}'s login endpoint.`); + } +} - if (!addListener || !removeListener) { - throw new TypeError('Emitter is not compatible'); - } +/*** + * @typedef {Object} VaultLoginResponse + * @property {{ + * client_token: string; + * accessor: string; + * policies: string[]; + * metadata: unknown; + * lease_duration: number; + * renewable: boolean; + * }} auth + */ - return { - addListener: addListener.bind(emitter), - removeListener: removeListener.bind(emitter) - }; +module.exports = { + retrieveToken, }; -const normalizeEvents = event => Array.isArray(event) ? event : [event]; - -const multiple = (emitter, event, options) => { - let cancel; - const ret = new Promise((resolve, reject) => { - options = { - rejectionEvents: ['error'], - multiArgs: false, - resolveImmediately: false, - ...options - }; - - if (!(options.count >= 0 && (options.count === Infinity || Number.isInteger(options.count)))) { - throw new TypeError('The `count` option should be at least 0 or more'); - } - - // Allow multiple events - const events = normalizeEvents(event); - const items = []; - const {addListener, removeListener} = normalizeEmitter(emitter); +/***/ }), - const onItem = (...args) => { - const value = options.multiArgs ? args : args[0]; +/***/ 154: +/***/ (function(module) { - if (options.filter && !options.filter(value)) { - return; - } +"use strict"; - items.push(value); +// rfc7231 6.1 +const statusCodeCacheableByDefault = new Set([ + 200, + 203, + 204, + 206, + 300, + 301, + 404, + 405, + 410, + 414, + 501, +]); - if (options.count === items.length) { - cancel(); - resolve(items); - } - }; +// This implementation does not understand partial responses (206) +const understoodStatuses = new Set([ + 200, + 203, + 204, + 300, + 301, + 302, + 303, + 307, + 308, + 404, + 405, + 410, + 414, + 501, +]); - const rejectHandler = error => { - cancel(); - reject(error); - }; +const errorStatusCodes = new Set([ + 500, + 502, + 503, + 504, +]); - cancel = () => { - for (const event of events) { - removeListener(event, onItem); - } +const hopByHopHeaders = { + date: true, // included, because we add Age update Date + connection: true, + 'keep-alive': true, + 'proxy-authenticate': true, + 'proxy-authorization': true, + te: true, + trailer: true, + 'transfer-encoding': true, + upgrade: true, +}; - for (const rejectionEvent of options.rejectionEvents) { - removeListener(rejectionEvent, rejectHandler); - } - }; +const excludedFromRevalidationUpdate = { + // Since the old body is reused, it doesn't make sense to change properties of the body + 'content-length': true, + 'content-encoding': true, + 'transfer-encoding': true, + 'content-range': true, +}; - for (const event of events) { - addListener(event, onItem); - } +function toNumberOrZero(s) { + const n = parseInt(s, 10); + return isFinite(n) ? n : 0; +} - for (const rejectionEvent of options.rejectionEvents) { - addListener(rejectionEvent, rejectHandler); - } +// RFC 5861 +function isErrorResponse(response) { + // consider undefined response as faulty + if(!response) { + return true + } + return errorStatusCodes.has(response.status); +} - if (options.resolveImmediately) { - resolve(items); - } - }); +function parseCacheControl(header) { + const cc = {}; + if (!header) return cc; - ret.cancel = cancel; - - if (typeof options.timeout === 'number') { - const timeout = pTimeout(ret, options.timeout); - timeout.cancel = cancel; - return timeout; - } + // TODO: When there is more than one value present for a given directive (e.g., two Expires header fields, multiple Cache-Control: max-age directives), + // the directive's value is considered invalid. Caches are encouraged to consider responses that have invalid freshness information to be stale + const parts = header.trim().split(/\s*,\s*/); // TODO: lame parsing + for (const part of parts) { + const [k, v] = part.split(/\s*=\s*/, 2); + cc[k] = v === undefined ? true : v.replace(/^"|"$/g, ''); // TODO: lame unquoting + } - return ret; -}; + return cc; +} -const pEvent = (emitter, event, options) => { - if (typeof options === 'function') { - options = {filter: options}; - } +function formatCacheControl(cc) { + let parts = []; + for (const k in cc) { + const v = cc[k]; + parts.push(v === true ? k : k + '=' + v); + } + if (!parts.length) { + return undefined; + } + return parts.join(', '); +} - options = { - ...options, - count: 1, - resolveImmediately: false - }; +module.exports = class CachePolicy { + constructor( + req, + res, + { + shared, + cacheHeuristic, + immutableMinTimeToLive, + ignoreCargoCult, + _fromObject, + } = {} + ) { + if (_fromObject) { + this._fromObject(_fromObject); + return; + } - const arrayPromise = multiple(emitter, event, options); - const promise = arrayPromise.then(array => array[0]); // eslint-disable-line promise/prefer-await-to-then - promise.cancel = arrayPromise.cancel; + if (!res || !res.headers) { + throw Error('Response headers missing'); + } + this._assertRequestHasHeaders(req); - return promise; -}; + this._responseTime = this.now(); + this._isShared = shared !== false; + this._cacheHeuristic = + undefined !== cacheHeuristic ? cacheHeuristic : 0.1; // 10% matches IE + this._immutableMinTtl = + undefined !== immutableMinTimeToLive + ? immutableMinTimeToLive + : 24 * 3600 * 1000; -module.exports = pEvent; -// TODO: Remove this for the next major release -module.exports.default = pEvent; + this._status = 'status' in res ? res.status : 200; + this._resHeaders = res.headers; + this._rescc = parseCacheControl(res.headers['cache-control']); + this._method = 'method' in req ? req.method : 'GET'; + this._url = req.url; + this._host = req.headers.host; + this._noAuthorization = !req.headers.authorization; + this._reqHeaders = res.headers.vary ? req.headers : null; // Don't keep all request headers if they won't be used + this._reqcc = parseCacheControl(req.headers['cache-control']); -module.exports.multiple = multiple; + // Assume that if someone uses legacy, non-standard uncecessary options they don't understand caching, + // so there's no point stricly adhering to the blindly copy&pasted directives. + if ( + ignoreCargoCult && + 'pre-check' in this._rescc && + 'post-check' in this._rescc + ) { + delete this._rescc['pre-check']; + delete this._rescc['post-check']; + delete this._rescc['no-cache']; + delete this._rescc['no-store']; + delete this._rescc['must-revalidate']; + this._resHeaders = Object.assign({}, this._resHeaders, { + 'cache-control': formatCacheControl(this._rescc), + }); + delete this._resHeaders.expires; + delete this._resHeaders.pragma; + } -module.exports.iterator = (emitter, event, options) => { - if (typeof options === 'function') { - options = {filter: options}; - } + // When the Cache-Control header field is not present in a request, caches MUST consider the no-cache request pragma-directive + // as having the same effect as if "Cache-Control: no-cache" were present (see Section 5.2.1). + if ( + res.headers['cache-control'] == null && + /no-cache/.test(res.headers.pragma) + ) { + this._rescc['no-cache'] = true; + } + } - // Allow multiple events - const events = normalizeEvents(event); + now() { + return Date.now(); + } - options = { - rejectionEvents: ['error'], - resolutionEvents: [], - limit: Infinity, - multiArgs: false, - ...options - }; + storable() { + // The "no-store" request directive indicates that a cache MUST NOT store any part of either this request or any response to it. + return !!( + !this._reqcc['no-store'] && + // A cache MUST NOT store a response to any request, unless: + // The request method is understood by the cache and defined as being cacheable, and + ('GET' === this._method || + 'HEAD' === this._method || + ('POST' === this._method && this._hasExplicitExpiration())) && + // the response status code is understood by the cache, and + understoodStatuses.has(this._status) && + // the "no-store" cache directive does not appear in request or response header fields, and + !this._rescc['no-store'] && + // the "private" response directive does not appear in the response, if the cache is shared, and + (!this._isShared || !this._rescc.private) && + // the Authorization header field does not appear in the request, if the cache is shared, + (!this._isShared || + this._noAuthorization || + this._allowsStoringAuthenticated()) && + // the response either: + // contains an Expires header field, or + (this._resHeaders.expires || + // contains a max-age response directive, or + // contains a s-maxage response directive and the cache is shared, or + // contains a public response directive. + this._rescc['max-age'] || + (this._isShared && this._rescc['s-maxage']) || + this._rescc.public || + // has a status code that is defined as cacheable by default + statusCodeCacheableByDefault.has(this._status)) + ); + } - const {limit} = options; - const isValidLimit = limit >= 0 && (limit === Infinity || Number.isInteger(limit)); - if (!isValidLimit) { - throw new TypeError('The `limit` option should be a non-negative integer or Infinity'); - } + _hasExplicitExpiration() { + // 4.2.1 Calculating Freshness Lifetime + return ( + (this._isShared && this._rescc['s-maxage']) || + this._rescc['max-age'] || + this._resHeaders.expires + ); + } - if (limit === 0) { - // Return an empty async iterator to avoid any further cost - return { - [Symbol.asyncIterator]() { - return this; - }, - async next() { - return { - done: true, - value: undefined - }; - } - }; - } + _assertRequestHasHeaders(req) { + if (!req || !req.headers) { + throw Error('Request headers missing'); + } + } - const {addListener, removeListener} = normalizeEmitter(emitter); + satisfiesWithoutRevalidation(req) { + this._assertRequestHasHeaders(req); - let isDone = false; - let error; - let hasPendingError = false; - const nextQueue = []; - const valueQueue = []; - let eventCount = 0; - let isLimitReached = false; + // When presented with a request, a cache MUST NOT reuse a stored response, unless: + // the presented request does not contain the no-cache pragma (Section 5.4), nor the no-cache cache directive, + // unless the stored response is successfully validated (Section 4.3), and + const requestCC = parseCacheControl(req.headers['cache-control']); + if (requestCC['no-cache'] || /no-cache/.test(req.headers.pragma)) { + return false; + } - const valueHandler = (...args) => { - eventCount++; - isLimitReached = eventCount === limit; + if (requestCC['max-age'] && this.age() > requestCC['max-age']) { + return false; + } - const value = options.multiArgs ? args : args[0]; + if ( + requestCC['min-fresh'] && + this.timeToLive() < 1000 * requestCC['min-fresh'] + ) { + return false; + } - if (nextQueue.length > 0) { - const {resolve} = nextQueue.shift(); + // the stored response is either: + // fresh, or allowed to be served stale + if (this.stale()) { + const allowsStale = + requestCC['max-stale'] && + !this._rescc['must-revalidate'] && + (true === requestCC['max-stale'] || + requestCC['max-stale'] > this.age() - this.maxAge()); + if (!allowsStale) { + return false; + } + } - resolve({done: false, value}); + return this._requestMatches(req, false); + } - if (isLimitReached) { - cancel(); - } + _requestMatches(req, allowHeadMethod) { + // The presented effective request URI and that of the stored response match, and + return ( + (!this._url || this._url === req.url) && + this._host === req.headers.host && + // the request method associated with the stored response allows it to be used for the presented request, and + (!req.method || + this._method === req.method || + (allowHeadMethod && 'HEAD' === req.method)) && + // selecting header fields nominated by the stored response (if any) match those presented, and + this._varyMatches(req) + ); + } - return; - } + _allowsStoringAuthenticated() { + // following Cache-Control response directives (Section 5.2.2) have such an effect: must-revalidate, public, and s-maxage. + return ( + this._rescc['must-revalidate'] || + this._rescc.public || + this._rescc['s-maxage'] + ); + } - valueQueue.push(value); + _varyMatches(req) { + if (!this._resHeaders.vary) { + return true; + } - if (isLimitReached) { - cancel(); - } - }; + // A Vary header field-value of "*" always fails to match + if (this._resHeaders.vary === '*') { + return false; + } - const cancel = () => { - isDone = true; - for (const event of events) { - removeListener(event, valueHandler); - } + const fields = this._resHeaders.vary + .trim() + .toLowerCase() + .split(/\s*,\s*/); + for (const name of fields) { + if (req.headers[name] !== this._reqHeaders[name]) return false; + } + return true; + } - for (const rejectionEvent of options.rejectionEvents) { - removeListener(rejectionEvent, rejectHandler); - } + _copyWithoutHopByHopHeaders(inHeaders) { + const headers = {}; + for (const name in inHeaders) { + if (hopByHopHeaders[name]) continue; + headers[name] = inHeaders[name]; + } + // 9.1. Connection + if (inHeaders.connection) { + const tokens = inHeaders.connection.trim().split(/\s*,\s*/); + for (const name of tokens) { + delete headers[name]; + } + } + if (headers.warning) { + const warnings = headers.warning.split(/,/).filter(warning => { + return !/^\s*1[0-9][0-9]/.test(warning); + }); + if (!warnings.length) { + delete headers.warning; + } else { + headers.warning = warnings.join(',').trim(); + } + } + return headers; + } - for (const resolutionEvent of options.resolutionEvents) { - removeListener(resolutionEvent, resolveHandler); - } - - while (nextQueue.length > 0) { - const {resolve} = nextQueue.shift(); - resolve({done: true, value: undefined}); - } - }; - - const rejectHandler = (...args) => { - error = options.multiArgs ? args : args[0]; - - if (nextQueue.length > 0) { - const {reject} = nextQueue.shift(); - reject(error); - } else { - hasPendingError = true; - } - - cancel(); - }; - - const resolveHandler = (...args) => { - const value = options.multiArgs ? args : args[0]; - - if (options.filter && !options.filter(value)) { - return; - } - - if (nextQueue.length > 0) { - const {resolve} = nextQueue.shift(); - resolve({done: true, value}); - } else { - valueQueue.push(value); - } - - cancel(); - }; + responseHeaders() { + const headers = this._copyWithoutHopByHopHeaders(this._resHeaders); + const age = this.age(); - for (const event of events) { - addListener(event, valueHandler); - } + // A cache SHOULD generate 113 warning if it heuristically chose a freshness + // lifetime greater than 24 hours and the response's age is greater than 24 hours. + if ( + age > 3600 * 24 && + !this._hasExplicitExpiration() && + this.maxAge() > 3600 * 24 + ) { + headers.warning = + (headers.warning ? `${headers.warning}, ` : '') + + '113 - "rfc7234 5.5.4"'; + } + headers.age = `${Math.round(age)}`; + headers.date = new Date(this.now()).toUTCString(); + return headers; + } - for (const rejectionEvent of options.rejectionEvents) { - addListener(rejectionEvent, rejectHandler); - } + /** + * Value of the Date response header or current time if Date was invalid + * @return timestamp + */ + date() { + const serverDate = Date.parse(this._resHeaders.date); + if (isFinite(serverDate)) { + return serverDate; + } + return this._responseTime; + } - for (const resolutionEvent of options.resolutionEvents) { - addListener(resolutionEvent, resolveHandler); - } + /** + * Value of the Age header, in seconds, updated for the current time. + * May be fractional. + * + * @return Number + */ + age() { + let age = this._ageValue(); - return { - [symbolAsyncIterator]() { - return this; - }, - async next() { - if (valueQueue.length > 0) { - const value = valueQueue.shift(); - return { - done: isDone && valueQueue.length === 0 && !isLimitReached, - value - }; - } + const residentTime = (this.now() - this._responseTime) / 1000; + return age + residentTime; + } - if (hasPendingError) { - hasPendingError = false; - throw error; - } + _ageValue() { + return toNumberOrZero(this._resHeaders.age); + } - if (isDone) { - return { - done: true, - value: undefined - }; - } + /** + * Value of applicable max-age (or heuristic equivalent) in seconds. This counts since response's `Date`. + * + * For an up-to-date value, see `timeToLive()`. + * + * @return Number + */ + maxAge() { + if (!this.storable() || this._rescc['no-cache']) { + return 0; + } - return new Promise((resolve, reject) => nextQueue.push({resolve, reject})); - }, - async return(value) { - cancel(); - return { - done: isDone, - value - }; - } - }; -}; + // Shared responses with cookies are cacheable according to the RFC, but IMHO it'd be unwise to do so by default + // so this implementation requires explicit opt-in via public header + if ( + this._isShared && + (this._resHeaders['set-cookie'] && + !this._rescc.public && + !this._rescc.immutable) + ) { + return 0; + } + if (this._resHeaders.vary === '*') { + return 0; + } -/***/ }), + if (this._isShared) { + if (this._rescc['proxy-revalidate']) { + return 0; + } + // if a response includes the s-maxage directive, a shared cache recipient MUST ignore the Expires field. + if (this._rescc['s-maxage']) { + return toNumberOrZero(this._rescc['s-maxage']); + } + } -/***/ 151: -/***/ (function(module, __unusedexports, __webpack_require__) { + // If a response includes a Cache-Control field with the max-age directive, a recipient MUST ignore the Expires field. + if (this._rescc['max-age']) { + return toNumberOrZero(this._rescc['max-age']); + } -// @ts-check -const core = __webpack_require__(470); + const defaultMinTtl = this._rescc.immutable ? this._immutableMinTtl : 0; -/*** - * Authenticate with Vault and retrieve a Vault token that can be used for requests. - * @param {string} method - * @param {import('got').Got} client - */ -async function retrieveToken(method, client) { - switch (method) { - case 'approle': { - const vaultRoleId = core.getInput('roleId', { required: true }); - const vaultSecretId = core.getInput('secretId', { required: true }); - return await getClientToken(client, method, { role_id: vaultRoleId, secret_id: vaultSecretId }); - } - case 'github': { - const githubToken = core.getInput('githubToken', { required: true }); - return await getClientToken(client, method, { token: githubToken }); - } - default: { - if (!method || method === 'token') { - return core.getInput('token', { required: true }); - } else { - /** @type {string} */ - const payload = core.getInput('authPayload', { required: true }); - if (!payload) { - throw Error('When using a custom authentication method, you must provide the payload'); - } - return await getClientToken(client, method, JSON.parse(payload.trim())); + const serverDate = this.date(); + if (this._resHeaders.expires) { + const expires = Date.parse(this._resHeaders.expires); + // A cache recipient MUST interpret invalid date formats, especially the value "0", as representing a time in the past (i.e., "already expired"). + if (Number.isNaN(expires) || expires < serverDate) { + return 0; } + return Math.max(defaultMinTtl, (expires - serverDate) / 1000); } - } -} - -/*** - * Call the appropriate login endpoint and parse out the token in the response. - * @param {import('got').Got} client - * @param {string} method - * @param {any} payload - */ -async function getClientToken(client, method, payload) { - /** @type {'json'} */ - const responseType = 'json'; - var options = { - json: payload, - responseType, - }; - - core.debug(`Retrieving Vault Token from v1/auth/${method}/login endpoint`); - /** @type {import('got').Response} */ - const response = await client.post(`v1/auth/${method}/login`, options); - if (response && response.body && response.body.auth && response.body.auth.client_token) { - core.debug('✔ Vault Token successfully retrieved'); + if (this._resHeaders['last-modified']) { + const lastModified = Date.parse(this._resHeaders['last-modified']); + if (isFinite(lastModified) && serverDate > lastModified) { + return Math.max( + defaultMinTtl, + ((serverDate - lastModified) / 1000) * this._cacheHeuristic + ); + } + } - core.startGroup('Token Info'); - core.debug(`Operating under policies: ${JSON.stringify(response.body.auth.policies)}`); - core.debug(`Token Metadata: ${JSON.stringify(response.body.auth.metadata)}`); - core.endGroup(); + return defaultMinTtl; + } - return response.body.auth.client_token; - } else { - throw Error(`Unable to retrieve token from ${method}'s login endpoint.`); + timeToLive() { + const age = this.maxAge() - this.age(); + const staleIfErrorAge = age + toNumberOrZero(this._rescc['stale-if-error']); + const staleWhileRevalidateAge = age + toNumberOrZero(this._rescc['stale-while-revalidate']); + return Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1000; } -} -/*** - * @typedef {Object} VaultLoginResponse - * @property {{ - * client_token: string; - * accessor: string; - * policies: string[]; - * metadata: unknown; - * lease_duration: number; - * renewable: boolean; - * }} auth - */ + stale() { + return this.maxAge() <= this.age(); + } -module.exports = { - retrieveToken, -}; + _useStaleIfError() { + return this.maxAge() + toNumberOrZero(this._rescc['stale-if-error']) > this.age(); + } + useStaleWhileRevalidate() { + return this.maxAge() + toNumberOrZero(this._rescc['stale-while-revalidate']) > this.age(); + } -/***/ }), + static fromObject(obj) { + return new this(undefined, undefined, { _fromObject: obj }); + } -/***/ 154: -/***/ (function(module) { + _fromObject(obj) { + if (this._responseTime) throw Error('Reinitialized'); + if (!obj || obj.v !== 1) throw Error('Invalid serialization'); -"use strict"; + this._responseTime = obj.t; + this._isShared = obj.sh; + this._cacheHeuristic = obj.ch; + this._immutableMinTtl = + obj.imm !== undefined ? obj.imm : 24 * 3600 * 1000; + this._status = obj.st; + this._resHeaders = obj.resh; + this._rescc = obj.rescc; + this._method = obj.m; + this._url = obj.u; + this._host = obj.h; + this._noAuthorization = obj.a; + this._reqHeaders = obj.reqh; + this._reqcc = obj.reqcc; + } -// rfc7231 6.1 -const statusCodeCacheableByDefault = new Set([ - 200, - 203, - 204, - 206, - 300, - 301, - 404, - 405, - 410, - 414, - 501, -]); - -// This implementation does not understand partial responses (206) -const understoodStatuses = new Set([ - 200, - 203, - 204, - 300, - 301, - 302, - 303, - 307, - 308, - 404, - 405, - 410, - 414, - 501, -]); - -const errorStatusCodes = new Set([ - 500, - 502, - 503, - 504, -]); - -const hopByHopHeaders = { - date: true, // included, because we add Age update Date - connection: true, - 'keep-alive': true, - 'proxy-authenticate': true, - 'proxy-authorization': true, - te: true, - trailer: true, - 'transfer-encoding': true, - upgrade: true, -}; - -const excludedFromRevalidationUpdate = { - // Since the old body is reused, it doesn't make sense to change properties of the body - 'content-length': true, - 'content-encoding': true, - 'transfer-encoding': true, - 'content-range': true, -}; - -function toNumberOrZero(s) { - const n = parseInt(s, 10); - return isFinite(n) ? n : 0; -} - -// RFC 5861 -function isErrorResponse(response) { - // consider undefined response as faulty - if(!response) { - return true - } - return errorStatusCodes.has(response.status); -} - -function parseCacheControl(header) { - const cc = {}; - if (!header) return cc; - - // TODO: When there is more than one value present for a given directive (e.g., two Expires header fields, multiple Cache-Control: max-age directives), - // the directive's value is considered invalid. Caches are encouraged to consider responses that have invalid freshness information to be stale - const parts = header.trim().split(/\s*,\s*/); // TODO: lame parsing - for (const part of parts) { - const [k, v] = part.split(/\s*=\s*/, 2); - cc[k] = v === undefined ? true : v.replace(/^"|"$/g, ''); // TODO: lame unquoting + toObject() { + return { + v: 1, + t: this._responseTime, + sh: this._isShared, + ch: this._cacheHeuristic, + imm: this._immutableMinTtl, + st: this._status, + resh: this._resHeaders, + rescc: this._rescc, + m: this._method, + u: this._url, + h: this._host, + a: this._noAuthorization, + reqh: this._reqHeaders, + reqcc: this._reqcc, + }; } - return cc; -} + /** + * Headers for sending to the origin server to revalidate stale response. + * Allows server to return 304 to allow reuse of the previous response. + * + * Hop by hop headers are always stripped. + * Revalidation headers may be added or removed, depending on request. + */ + revalidationHeaders(incomingReq) { + this._assertRequestHasHeaders(incomingReq); + const headers = this._copyWithoutHopByHopHeaders(incomingReq.headers); -function formatCacheControl(cc) { - let parts = []; - for (const k in cc) { - const v = cc[k]; - parts.push(v === true ? k : k + '=' + v); - } - if (!parts.length) { - return undefined; - } - return parts.join(', '); -} + // This implementation does not understand range requests + delete headers['if-range']; -module.exports = class CachePolicy { - constructor( - req, - res, - { - shared, - cacheHeuristic, - immutableMinTimeToLive, - ignoreCargoCult, - _fromObject, - } = {} - ) { - if (_fromObject) { - this._fromObject(_fromObject); - return; + if (!this._requestMatches(incomingReq, true) || !this.storable()) { + // revalidation allowed via HEAD + // not for the same resource, or wasn't allowed to be cached anyway + delete headers['if-none-match']; + delete headers['if-modified-since']; + return headers; } - if (!res || !res.headers) { - throw Error('Response headers missing'); + /* MUST send that entity-tag in any cache validation request (using If-Match or If-None-Match) if an entity-tag has been provided by the origin server. */ + if (this._resHeaders.etag) { + headers['if-none-match'] = headers['if-none-match'] + ? `${headers['if-none-match']}, ${this._resHeaders.etag}` + : this._resHeaders.etag; } - this._assertRequestHasHeaders(req); - this._responseTime = this.now(); - this._isShared = shared !== false; - this._cacheHeuristic = - undefined !== cacheHeuristic ? cacheHeuristic : 0.1; // 10% matches IE - this._immutableMinTtl = - undefined !== immutableMinTimeToLive - ? immutableMinTimeToLive - : 24 * 3600 * 1000; + // Clients MAY issue simple (non-subrange) GET requests with either weak validators or strong validators. Clients MUST NOT use weak validators in other forms of request. + const forbidsWeakValidators = + headers['accept-ranges'] || + headers['if-match'] || + headers['if-unmodified-since'] || + (this._method && this._method != 'GET'); - this._status = 'status' in res ? res.status : 200; - this._resHeaders = res.headers; - this._rescc = parseCacheControl(res.headers['cache-control']); - this._method = 'method' in req ? req.method : 'GET'; - this._url = req.url; - this._host = req.headers.host; - this._noAuthorization = !req.headers.authorization; - this._reqHeaders = res.headers.vary ? req.headers : null; // Don't keep all request headers if they won't be used - this._reqcc = parseCacheControl(req.headers['cache-control']); + /* SHOULD send the Last-Modified value in non-subrange cache validation requests (using If-Modified-Since) if only a Last-Modified value has been provided by the origin server. + Note: This implementation does not understand partial responses (206) */ + if (forbidsWeakValidators) { + delete headers['if-modified-since']; - // Assume that if someone uses legacy, non-standard uncecessary options they don't understand caching, - // so there's no point stricly adhering to the blindly copy&pasted directives. - if ( - ignoreCargoCult && - 'pre-check' in this._rescc && - 'post-check' in this._rescc + if (headers['if-none-match']) { + const etags = headers['if-none-match'] + .split(/,/) + .filter(etag => { + return !/^\s*W\//.test(etag); + }); + if (!etags.length) { + delete headers['if-none-match']; + } else { + headers['if-none-match'] = etags.join(',').trim(); + } + } + } else if ( + this._resHeaders['last-modified'] && + !headers['if-modified-since'] ) { - delete this._rescc['pre-check']; - delete this._rescc['post-check']; - delete this._rescc['no-cache']; - delete this._rescc['no-store']; - delete this._rescc['must-revalidate']; - this._resHeaders = Object.assign({}, this._resHeaders, { - 'cache-control': formatCacheControl(this._rescc), - }); - delete this._resHeaders.expires; - delete this._resHeaders.pragma; + headers['if-modified-since'] = this._resHeaders['last-modified']; } - // When the Cache-Control header field is not present in a request, caches MUST consider the no-cache request pragma-directive - // as having the same effect as if "Cache-Control: no-cache" were present (see Section 5.2.1). - if ( - res.headers['cache-control'] == null && - /no-cache/.test(res.headers.pragma) - ) { - this._rescc['no-cache'] = true; - } + return headers; } - now() { - return Date.now(); - } + /** + * Creates new CachePolicy with information combined from the previews response, + * and the new revalidation response. + * + * Returns {policy, modified} where modified is a boolean indicating + * whether the response body has been modified, and old cached body can't be used. + * + * @return {Object} {policy: CachePolicy, modified: Boolean} + */ + revalidatedPolicy(request, response) { + this._assertRequestHasHeaders(request); + if(this._useStaleIfError() && isErrorResponse(response)) { // I consider the revalidation request unsuccessful + return { + modified: false, + matches: false, + policy: this, + }; + } + if (!response || !response.headers) { + throw Error('Response headers missing'); + } - storable() { - // The "no-store" request directive indicates that a cache MUST NOT store any part of either this request or any response to it. - return !!( - !this._reqcc['no-store'] && - // A cache MUST NOT store a response to any request, unless: - // The request method is understood by the cache and defined as being cacheable, and - ('GET' === this._method || - 'HEAD' === this._method || - ('POST' === this._method && this._hasExplicitExpiration())) && - // the response status code is understood by the cache, and - understoodStatuses.has(this._status) && - // the "no-store" cache directive does not appear in request or response header fields, and - !this._rescc['no-store'] && - // the "private" response directive does not appear in the response, if the cache is shared, and - (!this._isShared || !this._rescc.private) && - // the Authorization header field does not appear in the request, if the cache is shared, - (!this._isShared || - this._noAuthorization || - this._allowsStoringAuthenticated()) && - // the response either: - // contains an Expires header field, or - (this._resHeaders.expires || - // contains a max-age response directive, or - // contains a s-maxage response directive and the cache is shared, or - // contains a public response directive. - this._rescc['max-age'] || - (this._isShared && this._rescc['s-maxage']) || - this._rescc.public || - // has a status code that is defined as cacheable by default - statusCodeCacheableByDefault.has(this._status)) - ); - } + // These aren't going to be supported exactly, since one CachePolicy object + // doesn't know about all the other cached objects. + let matches = false; + if (response.status !== undefined && response.status != 304) { + matches = false; + } else if ( + response.headers.etag && + !/^\s*W\//.test(response.headers.etag) + ) { + // "All of the stored responses with the same strong validator are selected. + // If none of the stored responses contain the same strong validator, + // then the cache MUST NOT use the new response to update any stored responses." + matches = + this._resHeaders.etag && + this._resHeaders.etag.replace(/^\s*W\//, '') === + response.headers.etag; + } else if (this._resHeaders.etag && response.headers.etag) { + // "If the new response contains a weak validator and that validator corresponds + // to one of the cache's stored responses, + // then the most recent of those matching stored responses is selected for update." + matches = + this._resHeaders.etag.replace(/^\s*W\//, '') === + response.headers.etag.replace(/^\s*W\//, ''); + } else if (this._resHeaders['last-modified']) { + matches = + this._resHeaders['last-modified'] === + response.headers['last-modified']; + } else { + // If the new response does not include any form of validator (such as in the case where + // a client generates an If-Modified-Since request from a source other than the Last-Modified + // response header field), and there is only one stored response, and that stored response also + // lacks a validator, then that stored response is selected for update. + if ( + !this._resHeaders.etag && + !this._resHeaders['last-modified'] && + !response.headers.etag && + !response.headers['last-modified'] + ) { + matches = true; + } + } - _hasExplicitExpiration() { - // 4.2.1 Calculating Freshness Lifetime - return ( - (this._isShared && this._rescc['s-maxage']) || - this._rescc['max-age'] || - this._resHeaders.expires - ); - } + if (!matches) { + return { + policy: new this.constructor(request, response), + // Client receiving 304 without body, even if it's invalid/mismatched has no option + // but to reuse a cached body. We don't have a good way to tell clients to do + // error recovery in such case. + modified: response.status != 304, + matches: false, + }; + } - _assertRequestHasHeaders(req) { - if (!req || !req.headers) { - throw Error('Request headers missing'); + // use other header fields provided in the 304 (Not Modified) response to replace all instances + // of the corresponding header fields in the stored response. + const headers = {}; + for (const k in this._resHeaders) { + headers[k] = + k in response.headers && !excludedFromRevalidationUpdate[k] + ? response.headers[k] + : this._resHeaders[k]; } + + const newResponse = Object.assign({}, response, { + status: this._status, + method: this._method, + headers, + }); + return { + policy: new this.constructor(request, newResponse, { + shared: this._isShared, + cacheHeuristic: this._cacheHeuristic, + immutableMinTimeToLive: this._immutableMinTtl, + }), + modified: false, + matches: true, + }; } +}; - satisfiesWithoutRevalidation(req) { - this._assertRequestHasHeaders(req); - // When presented with a request, a cache MUST NOT reuse a stored response, unless: - // the presented request does not contain the no-cache pragma (Section 5.4), nor the no-cache cache directive, - // unless the stored response is successfully validated (Section 4.3), and - const requestCC = parseCacheControl(req.headers['cache-control']); - if (requestCC['no-cache'] || /no-cache/.test(req.headers.pragma)) { - return false; - } +/***/ }), - if (requestCC['max-age'] && this.age() > requestCC['max-age']) { - return false; - } +/***/ 157: +/***/ (function(module, __unusedexports, __webpack_require__) { - if ( - requestCC['min-fresh'] && - this.timeToLive() < 1000 * requestCC['min-fresh'] - ) { - return false; - } +"use strict"; - // the stored response is either: - // fresh, or allowed to be served stale - if (this.stale()) { - const allowsStale = - requestCC['max-stale'] && - !this._rescc['must-revalidate'] && - (true === requestCC['max-stale'] || - requestCC['max-stale'] > this.age() - this.maxAge()); - if (!allowsStale) { - return false; - } - } +const http2 = __webpack_require__(565); +const agent = __webpack_require__(899); +const ClientRequest = __webpack_require__(181); +const IncomingMessage = __webpack_require__(750); +const auto = __webpack_require__(988); - return this._requestMatches(req, false); - } +const request = (url, options, callback) => { + return new ClientRequest(url, options, callback); +}; - _requestMatches(req, allowHeadMethod) { - // The presented effective request URI and that of the stored response match, and - return ( - (!this._url || this._url === req.url) && - this._host === req.headers.host && - // the request method associated with the stored response allows it to be used for the presented request, and - (!req.method || - this._method === req.method || - (allowHeadMethod && 'HEAD' === req.method)) && - // selecting header fields nominated by the stored response (if any) match those presented, and - this._varyMatches(req) - ); - } +const get = (url, options, callback) => { + // eslint-disable-next-line unicorn/prevent-abbreviations + const req = new ClientRequest(url, options, callback); + req.end(); - _allowsStoringAuthenticated() { - // following Cache-Control response directives (Section 5.2.2) have such an effect: must-revalidate, public, and s-maxage. - return ( - this._rescc['must-revalidate'] || - this._rescc.public || - this._rescc['s-maxage'] - ); - } + return req; +}; - _varyMatches(req) { - if (!this._resHeaders.vary) { - return true; - } +module.exports = { + ...http2, + ClientRequest, + IncomingMessage, + ...agent, + request, + get, + auto +}; - // A Vary header field-value of "*" always fails to match - if (this._resHeaders.vary === '*') { - return false; - } - const fields = this._resHeaders.vary - .trim() - .toLowerCase() - .split(/\s*,\s*/); - for (const name of fields) { - if (req.headers[name] !== this._reqHeaders[name]) return false; - } - return true; - } +/***/ }), - _copyWithoutHopByHopHeaders(inHeaders) { - const headers = {}; - for (const name in inHeaders) { - if (hopByHopHeaders[name]) continue; - headers[name] = inHeaders[name]; - } - // 9.1. Connection - if (inHeaders.connection) { - const tokens = inHeaders.connection.trim().split(/\s*,\s*/); - for (const name of tokens) { - delete headers[name]; - } - } - if (headers.warning) { - const warnings = headers.warning.split(/,/).filter(warning => { - return !/^\s*1[0-9][0-9]/.test(warning); - }); - if (!warnings.length) { - delete headers.warning; - } else { - headers.warning = warnings.join(',').trim(); - } - } - return headers; - } +/***/ 181: +/***/ (function(module, __unusedexports, __webpack_require__) { - responseHeaders() { - const headers = this._copyWithoutHopByHopHeaders(this._resHeaders); - const age = this.age(); +"use strict"; - // A cache SHOULD generate 113 warning if it heuristically chose a freshness - // lifetime greater than 24 hours and the response's age is greater than 24 hours. - if ( - age > 3600 * 24 && - !this._hasExplicitExpiration() && - this.maxAge() > 3600 * 24 - ) { - headers.warning = - (headers.warning ? `${headers.warning}, ` : '') + - '113 - "rfc7234 5.5.4"'; - } - headers.age = `${Math.round(age)}`; - headers.date = new Date(this.now()).toUTCString(); - return headers; - } +const http2 = __webpack_require__(565); +const {Writable} = __webpack_require__(413); +const {Agent, globalAgent} = __webpack_require__(899); +const IncomingMessage = __webpack_require__(750); +const urlToOptions = __webpack_require__(507); +const proxyEvents = __webpack_require__(231); +const isRequestPseudoHeader = __webpack_require__(723); +const { + ERR_INVALID_ARG_TYPE, + ERR_INVALID_PROTOCOL, + ERR_HTTP_HEADERS_SENT, + ERR_INVALID_HTTP_TOKEN, + ERR_HTTP_INVALID_HEADER_VALUE, + ERR_INVALID_CHAR +} = __webpack_require__(699); - /** - * Value of the Date response header or current time if Date was invalid - * @return timestamp - */ - date() { - const serverDate = Date.parse(this._resHeaders.date); - if (isFinite(serverDate)) { - return serverDate; - } - return this._responseTime; - } +const { + HTTP2_HEADER_STATUS, + HTTP2_HEADER_METHOD, + HTTP2_HEADER_PATH, + HTTP2_METHOD_CONNECT +} = http2.constants; + +const kHeaders = Symbol('headers'); +const kOrigin = Symbol('origin'); +const kSession = Symbol('session'); +const kOptions = Symbol('options'); +const kFlushedHeaders = Symbol('flushedHeaders'); +const kJobs = Symbol('jobs'); + +const isValidHttpToken = /^[\^`\-\w!#$%&*+.|~]+$/; +const isInvalidHeaderValue = /[^\t\u0020-\u007E\u0080-\u00FF]/; + +class ClientRequest extends Writable { + constructor(input, options, callback) { + super({ + autoDestroy: false + }); - /** - * Value of the Age header, in seconds, updated for the current time. - * May be fractional. - * - * @return Number - */ - age() { - let age = this._ageValue(); + const hasInput = typeof input === 'string' || input instanceof URL; + if (hasInput) { + input = urlToOptions(input instanceof URL ? input : new URL(input)); + } - const residentTime = (this.now() - this._responseTime) / 1000; - return age + residentTime; - } + if (typeof options === 'function' || options === undefined) { + // (options, callback) + callback = options; + options = hasInput ? input : {...input}; + } else { + // (input, options, callback) + options = {...input, ...options}; + } - _ageValue() { - return toNumberOrZero(this._resHeaders.age); - } + if (options.h2session) { + this[kSession] = options.h2session; + } else if (options.agent === false) { + this.agent = new Agent({maxFreeSessions: 0}); + } else if (typeof options.agent === 'undefined' || options.agent === null) { + if (typeof options.createConnection === 'function') { + // This is a workaround - we don't have to create the session on our own. + this.agent = new Agent({maxFreeSessions: 0}); + this.agent.createConnection = options.createConnection; + } else { + this.agent = globalAgent; + } + } else if (typeof options.agent.request === 'function') { + this.agent = options.agent; + } else { + throw new ERR_INVALID_ARG_TYPE('options.agent', ['Agent-like Object', 'undefined', 'false'], options.agent); + } - /** - * Value of applicable max-age (or heuristic equivalent) in seconds. This counts since response's `Date`. - * - * For an up-to-date value, see `timeToLive()`. - * - * @return Number - */ - maxAge() { - if (!this.storable() || this._rescc['no-cache']) { - return 0; - } + if (options.protocol && options.protocol !== 'https:') { + throw new ERR_INVALID_PROTOCOL(options.protocol, 'https:'); + } - // Shared responses with cookies are cacheable according to the RFC, but IMHO it'd be unwise to do so by default - // so this implementation requires explicit opt-in via public header - if ( - this._isShared && - (this._resHeaders['set-cookie'] && - !this._rescc.public && - !this._rescc.immutable) - ) { - return 0; - } + const port = options.port || options.defaultPort || (this.agent && this.agent.defaultPort) || 443; + const host = options.hostname || options.host || 'localhost'; - if (this._resHeaders.vary === '*') { - return 0; - } + // Don't enforce the origin via options. It may be changed in an Agent. + delete options.hostname; + delete options.host; + delete options.port; - if (this._isShared) { - if (this._rescc['proxy-revalidate']) { - return 0; - } - // if a response includes the s-maxage directive, a shared cache recipient MUST ignore the Expires field. - if (this._rescc['s-maxage']) { - return toNumberOrZero(this._rescc['s-maxage']); - } - } + const {timeout} = options; + options.timeout = undefined; - // If a response includes a Cache-Control field with the max-age directive, a recipient MUST ignore the Expires field. - if (this._rescc['max-age']) { - return toNumberOrZero(this._rescc['max-age']); - } + this[kHeaders] = Object.create(null); + this[kJobs] = []; - const defaultMinTtl = this._rescc.immutable ? this._immutableMinTtl : 0; + this.socket = null; + this.connection = null; - const serverDate = this.date(); - if (this._resHeaders.expires) { - const expires = Date.parse(this._resHeaders.expires); - // A cache recipient MUST interpret invalid date formats, especially the value "0", as representing a time in the past (i.e., "already expired"). - if (Number.isNaN(expires) || expires < serverDate) { - return 0; - } - return Math.max(defaultMinTtl, (expires - serverDate) / 1000); - } + this.method = options.method || 'GET'; + this.path = options.path; - if (this._resHeaders['last-modified']) { - const lastModified = Date.parse(this._resHeaders['last-modified']); - if (isFinite(lastModified) && serverDate > lastModified) { - return Math.max( - defaultMinTtl, - ((serverDate - lastModified) / 1000) * this._cacheHeuristic - ); - } - } + this.res = null; + this.aborted = false; + this.reusedSocket = false; - return defaultMinTtl; - } + if (options.headers) { + for (const [header, value] of Object.entries(options.headers)) { + this.setHeader(header, value); + } + } - timeToLive() { - const age = this.maxAge() - this.age(); - const staleIfErrorAge = age + toNumberOrZero(this._rescc['stale-if-error']); - const staleWhileRevalidateAge = age + toNumberOrZero(this._rescc['stale-while-revalidate']); - return Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1000; - } + if (options.auth && !('authorization' in this[kHeaders])) { + this[kHeaders].authorization = 'Basic ' + Buffer.from(options.auth).toString('base64'); + } - stale() { - return this.maxAge() <= this.age(); - } + options.session = options.tlsSession; + options.path = options.socketPath; - _useStaleIfError() { - return this.maxAge() + toNumberOrZero(this._rescc['stale-if-error']) > this.age(); - } + this[kOptions] = options; - useStaleWhileRevalidate() { - return this.maxAge() + toNumberOrZero(this._rescc['stale-while-revalidate']) > this.age(); - } + // Clients that generate HTTP/2 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field. + if (port === 443) { + this[kOrigin] = `https://${host}`; - static fromObject(obj) { - return new this(undefined, undefined, { _fromObject: obj }); - } + if (!(':authority' in this[kHeaders])) { + this[kHeaders][':authority'] = host; + } + } else { + this[kOrigin] = `https://${host}:${port}`; - _fromObject(obj) { - if (this._responseTime) throw Error('Reinitialized'); - if (!obj || obj.v !== 1) throw Error('Invalid serialization'); + if (!(':authority' in this[kHeaders])) { + this[kHeaders][':authority'] = `${host}:${port}`; + } + } - this._responseTime = obj.t; - this._isShared = obj.sh; - this._cacheHeuristic = obj.ch; - this._immutableMinTtl = - obj.imm !== undefined ? obj.imm : 24 * 3600 * 1000; - this._status = obj.st; - this._resHeaders = obj.resh; - this._rescc = obj.rescc; - this._method = obj.m; - this._url = obj.u; - this._host = obj.h; - this._noAuthorization = obj.a; - this._reqHeaders = obj.reqh; - this._reqcc = obj.reqcc; - } + if (timeout) { + this.setTimeout(timeout); + } - toObject() { - return { - v: 1, - t: this._responseTime, - sh: this._isShared, - ch: this._cacheHeuristic, - imm: this._immutableMinTtl, - st: this._status, - resh: this._resHeaders, - rescc: this._rescc, - m: this._method, - u: this._url, - h: this._host, - a: this._noAuthorization, - reqh: this._reqHeaders, - reqcc: this._reqcc, - }; - } + if (callback) { + this.once('response', callback); + } - /** - * Headers for sending to the origin server to revalidate stale response. - * Allows server to return 304 to allow reuse of the previous response. - * - * Hop by hop headers are always stripped. - * Revalidation headers may be added or removed, depending on request. - */ - revalidationHeaders(incomingReq) { - this._assertRequestHasHeaders(incomingReq); - const headers = this._copyWithoutHopByHopHeaders(incomingReq.headers); + this[kFlushedHeaders] = false; + } - // This implementation does not understand range requests - delete headers['if-range']; + get method() { + return this[kHeaders][HTTP2_HEADER_METHOD]; + } - if (!this._requestMatches(incomingReq, true) || !this.storable()) { - // revalidation allowed via HEAD - // not for the same resource, or wasn't allowed to be cached anyway - delete headers['if-none-match']; - delete headers['if-modified-since']; - return headers; - } + set method(value) { + if (value) { + this[kHeaders][HTTP2_HEADER_METHOD] = value.toUpperCase(); + } + } - /* MUST send that entity-tag in any cache validation request (using If-Match or If-None-Match) if an entity-tag has been provided by the origin server. */ - if (this._resHeaders.etag) { - headers['if-none-match'] = headers['if-none-match'] - ? `${headers['if-none-match']}, ${this._resHeaders.etag}` - : this._resHeaders.etag; - } + get path() { + return this[kHeaders][HTTP2_HEADER_PATH]; + } - // Clients MAY issue simple (non-subrange) GET requests with either weak validators or strong validators. Clients MUST NOT use weak validators in other forms of request. - const forbidsWeakValidators = - headers['accept-ranges'] || - headers['if-match'] || - headers['if-unmodified-since'] || - (this._method && this._method != 'GET'); + set path(value) { + if (value) { + this[kHeaders][HTTP2_HEADER_PATH] = value; + } + } - /* SHOULD send the Last-Modified value in non-subrange cache validation requests (using If-Modified-Since) if only a Last-Modified value has been provided by the origin server. - Note: This implementation does not understand partial responses (206) */ - if (forbidsWeakValidators) { - delete headers['if-modified-since']; + get _mustNotHaveABody() { + return this.method === 'GET' || this.method === 'HEAD' || this.method === 'DELETE'; + } - if (headers['if-none-match']) { - const etags = headers['if-none-match'] - .split(/,/) - .filter(etag => { - return !/^\s*W\//.test(etag); - }); - if (!etags.length) { - delete headers['if-none-match']; - } else { - headers['if-none-match'] = etags.join(',').trim(); - } - } - } else if ( - this._resHeaders['last-modified'] && - !headers['if-modified-since'] - ) { - headers['if-modified-since'] = this._resHeaders['last-modified']; - } + _write(chunk, encoding, callback) { + // https://github.com/nodejs/node/blob/654df09ae0c5e17d1b52a900a545f0664d8c7627/lib/internal/http2/util.js#L148-L156 + if (this._mustNotHaveABody) { + callback(new Error('The GET, HEAD and DELETE methods must NOT have a body')); + /* istanbul ignore next: Node.js 12 throws directly */ + return; + } - return headers; - } + this.flushHeaders(); - /** - * Creates new CachePolicy with information combined from the previews response, - * and the new revalidation response. - * - * Returns {policy, modified} where modified is a boolean indicating - * whether the response body has been modified, and old cached body can't be used. - * - * @return {Object} {policy: CachePolicy, modified: Boolean} - */ - revalidatedPolicy(request, response) { - this._assertRequestHasHeaders(request); - if(this._useStaleIfError() && isErrorResponse(response)) { // I consider the revalidation request unsuccessful - return { - modified: false, - matches: false, - policy: this, - }; - } - if (!response || !response.headers) { - throw Error('Response headers missing'); - } + const callWrite = () => this._request.write(chunk, encoding, callback); + if (this._request) { + callWrite(); + } else { + this[kJobs].push(callWrite); + } + } - // These aren't going to be supported exactly, since one CachePolicy object - // doesn't know about all the other cached objects. - let matches = false; - if (response.status !== undefined && response.status != 304) { - matches = false; - } else if ( - response.headers.etag && - !/^\s*W\//.test(response.headers.etag) - ) { - // "All of the stored responses with the same strong validator are selected. - // If none of the stored responses contain the same strong validator, - // then the cache MUST NOT use the new response to update any stored responses." - matches = - this._resHeaders.etag && - this._resHeaders.etag.replace(/^\s*W\//, '') === - response.headers.etag; - } else if (this._resHeaders.etag && response.headers.etag) { - // "If the new response contains a weak validator and that validator corresponds - // to one of the cache's stored responses, - // then the most recent of those matching stored responses is selected for update." - matches = - this._resHeaders.etag.replace(/^\s*W\//, '') === - response.headers.etag.replace(/^\s*W\//, ''); - } else if (this._resHeaders['last-modified']) { - matches = - this._resHeaders['last-modified'] === - response.headers['last-modified']; - } else { - // If the new response does not include any form of validator (such as in the case where - // a client generates an If-Modified-Since request from a source other than the Last-Modified - // response header field), and there is only one stored response, and that stored response also - // lacks a validator, then that stored response is selected for update. - if ( - !this._resHeaders.etag && - !this._resHeaders['last-modified'] && - !response.headers.etag && - !response.headers['last-modified'] - ) { - matches = true; - } - } + _final(callback) { + if (this.destroyed) { + return; + } - if (!matches) { - return { - policy: new this.constructor(request, response), - // Client receiving 304 without body, even if it's invalid/mismatched has no option - // but to reuse a cached body. We don't have a good way to tell clients to do - // error recovery in such case. - modified: response.status != 304, - matches: false, - }; - } + this.flushHeaders(); - // use other header fields provided in the 304 (Not Modified) response to replace all instances - // of the corresponding header fields in the stored response. - const headers = {}; - for (const k in this._resHeaders) { - headers[k] = - k in response.headers && !excludedFromRevalidationUpdate[k] - ? response.headers[k] - : this._resHeaders[k]; - } + const callEnd = () => { + // For GET, HEAD and DELETE + if (this._mustNotHaveABody) { + callback(); + return; + } - const newResponse = Object.assign({}, response, { - status: this._status, - method: this._method, - headers, - }); - return { - policy: new this.constructor(request, newResponse, { - shared: this._isShared, - cacheHeuristic: this._cacheHeuristic, - immutableMinTimeToLive: this._immutableMinTtl, - }), - modified: false, - matches: true, - }; - } -}; + this._request.end(callback); + }; + + if (this._request) { + callEnd(); + } else { + this[kJobs].push(callEnd); + } + } + + abort() { + if (this.res && this.res.complete) { + return; + } + + if (!this.aborted) { + process.nextTick(() => this.emit('abort')); + } + + this.aborted = true; + + this.destroy(); + } + + _destroy(error, callback) { + if (this.res) { + this.res._dump(); + } + + if (this._request) { + this._request.destroy(); + } + + callback(error); + } + + async flushHeaders() { + if (this[kFlushedHeaders] || this.destroyed) { + return; + } + + this[kFlushedHeaders] = true; + + const isConnectMethod = this.method === HTTP2_METHOD_CONNECT; + + // The real magic is here + const onStream = stream => { + this._request = stream; + + if (this.destroyed) { + stream.destroy(); + return; + } + + // Forwards `timeout`, `continue`, `close` and `error` events to this instance. + if (!isConnectMethod) { + proxyEvents(stream, this, ['timeout', 'continue', 'close', 'error']); + } + + // Wait for the `finish` event. We don't want to emit the `response` event + // before `request.end()` is called. + const waitForEnd = fn => { + return (...args) => { + if (!this.writable && !this.destroyed) { + fn(...args); + } else { + this.once('finish', () => { + fn(...args); + }); + } + }; + }; + + // This event tells we are ready to listen for the data. + stream.once('response', waitForEnd((headers, flags, rawHeaders) => { + // If we were to emit raw request stream, it would be as fast as the native approach. + // Note that wrapping the raw stream in a Proxy instance won't improve the performance (already tested it). + const response = new IncomingMessage(this.socket, stream.readableHighWaterMark); + this.res = response; + + response.req = this; + response.statusCode = headers[HTTP2_HEADER_STATUS]; + response.headers = headers; + response.rawHeaders = rawHeaders; + + response.once('end', () => { + if (this.aborted) { + response.aborted = true; + response.emit('aborted'); + } else { + response.complete = true; + + // Has no effect, just be consistent with the Node.js behavior + response.socket = null; + response.connection = null; + } + }); + + if (isConnectMethod) { + response.upgrade = true; + + // The HTTP1 API says the socket is detached here, + // but we can't do that so we pass the original HTTP2 request. + if (this.emit('connect', response, stream, Buffer.alloc(0))) { + this.emit('close'); + } else { + // No listeners attached, destroy the original request. + stream.destroy(); + } + } else { + // Forwards data + stream.on('data', chunk => { + if (!response._dumped && !response.push(chunk)) { + stream.pause(); + } + }); + + stream.once('end', () => { + response.push(null); + }); + + if (!this.emit('response', response)) { + // No listeners attached, dump the response. + response._dump(); + } + } + })); + + // Emits `information` event + stream.once('headers', waitForEnd( + headers => this.emit('information', {statusCode: headers[HTTP2_HEADER_STATUS]}) + )); + + stream.once('trailers', waitForEnd((trailers, flags, rawTrailers) => { + const {res} = this; + + // Assigns trailers to the response object. + res.trailers = trailers; + res.rawTrailers = rawTrailers; + })); + + const {socket} = stream.session; + this.socket = socket; + this.connection = socket; + + for (const job of this[kJobs]) { + job(); + } + + this.emit('socket', this.socket); + }; + + // Makes a HTTP2 request + if (this[kSession]) { + try { + onStream(this[kSession].request(this[kHeaders])); + } catch (error) { + this.emit('error', error); + } + } else { + this.reusedSocket = true; + + try { + onStream(await this.agent.request(this[kOrigin], this[kOptions], this[kHeaders])); + } catch (error) { + this.emit('error', error); + } + } + } + + getHeader(name) { + if (typeof name !== 'string') { + throw new ERR_INVALID_ARG_TYPE('name', 'string', name); + } + + return this[kHeaders][name.toLowerCase()]; + } + + get headersSent() { + return this[kFlushedHeaders]; + } + + removeHeader(name) { + if (typeof name !== 'string') { + throw new ERR_INVALID_ARG_TYPE('name', 'string', name); + } + + if (this.headersSent) { + throw new ERR_HTTP_HEADERS_SENT('remove'); + } + + delete this[kHeaders][name.toLowerCase()]; + } + + setHeader(name, value) { + if (this.headersSent) { + throw new ERR_HTTP_HEADERS_SENT('set'); + } + + if (typeof name !== 'string' || (!isValidHttpToken.test(name) && !isRequestPseudoHeader(name))) { + throw new ERR_INVALID_HTTP_TOKEN('Header name', name); + } + + if (typeof value === 'undefined') { + throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name); + } + + if (isInvalidHeaderValue.test(value)) { + throw new ERR_INVALID_CHAR('header content', name); + } + + this[kHeaders][name.toLowerCase()] = value; + } + + setNoDelay() { + // HTTP2 sockets cannot be malformed, do nothing. + } + + setSocketKeepAlive() { + // HTTP2 sockets cannot be malformed, do nothing. + } + + setTimeout(ms, callback) { + const applyTimeout = () => this._request.setTimeout(ms, callback); + + if (this._request) { + applyTimeout(); + } else { + this[kJobs].push(applyTimeout); + } + + return this; + } + + get maxHeadersCount() { + if (!this.destroyed && this._request) { + return this._request.session.localSettings.maxHeaderListSize; + } + + return undefined; + } + + set maxHeadersCount(_value) { + // Updating HTTP2 settings would affect all requests, do nothing. + } +} + +module.exports = ClientRequest; /***/ }), -/***/ 164: -/***/ (function(__unusedmodule, exports, __webpack_require__) { +/***/ 189: +/***/ (function(__unusedmodule, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const url_1 = __webpack_require__(835); -const is_1 = __webpack_require__(534); -function merge(target, ...sources) { - for (const source of sources) { - for (const [key, sourceValue] of Object.entries(source)) { - const targetValue = target[key]; - if (is_1.default.urlInstance(targetValue) && is_1.default.string(sourceValue)) { - // @ts-ignore TS doesn't recognise Target accepts string keys - target[key] = new url_1.URL(sourceValue, targetValue); - } - else if (is_1.default.plainObject(sourceValue)) { - if (is_1.default.plainObject(targetValue)) { - // @ts-ignore TS doesn't recognise Target accepts string keys - target[key] = merge({}, targetValue, sourceValue); - } - else { - // @ts-ignore TS doesn't recognise Target accepts string keys - target[key] = merge({}, sourceValue); - } - } - else if (is_1.default.array(sourceValue)) { - // @ts-ignore TS doesn't recognise Target accepts string keys - target[key] = sourceValue.slice(); - } - else { - // @ts-ignore TS doesn't recognise Target accepts string keys - target[key] = sourceValue; - } - } - } - return target; -} -exports.default = merge; +const alreadyWarned = new Set(); +exports.default = (message) => { + if (alreadyWarned.has(message)) { + return; + } + alreadyWarned.add(message); + // @ts-expect-error Missing types. + process.emitWarning(`Got: ${message}`, { + type: 'DeprecationWarning' + }); +}; /***/ }), @@ -2431,315 +2140,42 @@ exports.parse = function (s) { /***/ }), -/***/ 210: +/***/ 211: /***/ (function(module) { -"use strict"; +module.exports = require("https"); +/***/ }), -// We define these manually to ensure they're always copied -// even if they would move up the prototype chain -// https://nodejs.org/api/http.html#http_class_http_incomingmessage -const knownProps = [ - 'destroy', - 'setTimeout', - 'socket', - 'headers', - 'trailers', - 'rawHeaders', - 'statusCode', - 'httpVersion', - 'httpVersionMinor', - 'httpVersionMajor', - 'rawTrailers', - 'statusMessage' -]; +/***/ 231: +/***/ (function(module) { -module.exports = (fromStream, toStream) => { - const fromProps = new Set(Object.keys(fromStream).concat(knownProps)); +"use strict"; - for (const prop of fromProps) { - // Don't overwrite existing properties - if (prop in toStream) { - continue; - } - toStream[prop] = typeof fromStream[prop] === 'function' ? fromStream[prop].bind(fromStream) : fromStream[prop]; +module.exports = (from, to, events) => { + for (const event of events) { + from.on(event, (...args) => to.emit(event, ...args)); } }; /***/ }), -/***/ 211: -/***/ (function(module) { - -module.exports = require("https"); - -/***/ }), - -/***/ 215: +/***/ 291: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const net = __webpack_require__(631); -const unhandle_1 = __webpack_require__(668); -const reentry = Symbol('reentry'); -const noop = () => { }; -class TimeoutError extends Error { - constructor(threshold, event) { - super(`Timeout awaiting '${event}' for ${threshold}ms`); - this.event = event; - this.name = 'TimeoutError'; - this.code = 'ETIMEDOUT'; +const is_1 = __webpack_require__(534); +function deepFreeze(object) { + for (const value of Object.values(object)) { + if (is_1.default.plainObject(value) || is_1.default.array(value)) { + deepFreeze(value); + } } -} -exports.TimeoutError = TimeoutError; -exports.default = (request, delays, options) => { - if (Reflect.has(request, reentry)) { - return noop; - } - request[reentry] = true; - const cancelers = []; - const { once, unhandleAll } = unhandle_1.default(); - const addTimeout = (delay, callback, event) => { - var _a, _b; - const timeout = setTimeout(callback, delay, delay, event); - (_b = (_a = timeout).unref) === null || _b === void 0 ? void 0 : _b.call(_a); - const cancel = () => { - clearTimeout(timeout); - }; - cancelers.push(cancel); - return cancel; - }; - const { host, hostname } = options; - const timeoutHandler = (delay, event) => { - if (request.socket) { - // @ts-ignore We do not want the `socket hang up` error - request.socket._hadError = true; - } - request.abort(); - request.emit('error', new TimeoutError(delay, event)); - }; - const cancelTimeouts = () => { - for (const cancel of cancelers) { - cancel(); - } - unhandleAll(); - }; - request.once('error', error => { - cancelTimeouts(); - // Save original behavior - if (request.listenerCount('error') === 0) { - throw error; - } - }); - request.once('abort', cancelTimeouts); - once(request, 'response', (response) => { - once(response, 'end', cancelTimeouts); - }); - if (typeof delays.request !== 'undefined') { - addTimeout(delays.request, timeoutHandler, 'request'); - } - if (typeof delays.socket !== 'undefined') { - const socketTimeoutHandler = () => { - timeoutHandler(delays.socket, 'socket'); - }; - request.setTimeout(delays.socket, socketTimeoutHandler); - // `request.setTimeout(0)` causes a memory leak. - // We can just remove the listener and forget about the timer - it's unreffed. - // See https://github.com/sindresorhus/got/issues/690 - cancelers.push(() => { - request.removeListener('timeout', socketTimeoutHandler); - }); - } - once(request, 'socket', (socket) => { - var _a; - // @ts-ignore Node typings doesn't have this property - const { socketPath } = request; - /* istanbul ignore next: hard to test */ - if (socket.connecting) { - const hasPath = Boolean((socketPath !== null && socketPath !== void 0 ? socketPath : net.isIP((_a = (hostname !== null && hostname !== void 0 ? hostname : host), (_a !== null && _a !== void 0 ? _a : ''))) !== 0)); - if (typeof delays.lookup !== 'undefined' && !hasPath && typeof socket.address().address === 'undefined') { - const cancelTimeout = addTimeout(delays.lookup, timeoutHandler, 'lookup'); - once(socket, 'lookup', cancelTimeout); - } - if (typeof delays.connect !== 'undefined') { - const timeConnect = () => addTimeout(delays.connect, timeoutHandler, 'connect'); - if (hasPath) { - once(socket, 'connect', timeConnect()); - } - else { - once(socket, 'lookup', (error) => { - if (error === null) { - once(socket, 'connect', timeConnect()); - } - }); - } - } - if (typeof delays.secureConnect !== 'undefined' && options.protocol === 'https:') { - once(socket, 'connect', () => { - const cancelTimeout = addTimeout(delays.secureConnect, timeoutHandler, 'secureConnect'); - once(socket, 'secureConnect', cancelTimeout); - }); - } - } - if (typeof delays.send !== 'undefined') { - const timeRequest = () => addTimeout(delays.send, timeoutHandler, 'send'); - /* istanbul ignore next: hard to test */ - if (socket.connecting) { - once(socket, 'connect', () => { - once(request, 'upload-complete', timeRequest()); - }); - } - else { - once(request, 'upload-complete', timeRequest()); - } - } - }); - if (typeof delays.response !== 'undefined') { - once(request, 'upload-complete', () => { - const cancelTimeout = addTimeout(delays.response, timeoutHandler, 'response'); - once(request, 'response', cancelTimeout); - }); - } - return cancelTimeouts; -}; - - -/***/ }), - -/***/ 219: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const is_1 = __webpack_require__(534); -exports.default = (body) => is_1.default.nodeStream(body) && is_1.default.function_(body.getBoundary); - - -/***/ }), - -/***/ 232: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs_1 = __webpack_require__(747); -const util_1 = __webpack_require__(669); -const is_1 = __webpack_require__(534); -const is_form_data_1 = __webpack_require__(219); -const statAsync = util_1.promisify(fs_1.stat); -exports.default = async (options) => { - const { body, headers } = options; - if (headers && 'content-length' in headers) { - return Number(headers['content-length']); - } - if (!body) { - return 0; - } - if (is_1.default.string(body)) { - return Buffer.byteLength(body); - } - if (is_1.default.buffer(body)) { - return body.length; - } - if (is_form_data_1.default(body)) { - return util_1.promisify(body.getLength.bind(body))(); - } - if (body instanceof fs_1.ReadStream) { - const { size } = await statAsync(body.path); - return size; - } - return undefined; -}; - - -/***/ }), - -/***/ 234: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const decompressResponse = __webpack_require__(861); -const mimicResponse = __webpack_require__(89); -const stream = __webpack_require__(413); -const util_1 = __webpack_require__(669); -const progress_1 = __webpack_require__(489); -const pipeline = util_1.promisify(stream.pipeline); -exports.default = async (response, options, emitter) => { - var _a; - const downloadBodySize = Number(response.headers['content-length']) || undefined; - const progressStream = progress_1.createProgressStream('downloadProgress', emitter, downloadBodySize); - mimicResponse(response, progressStream); - const newResponse = (options.decompress && - options.method !== 'HEAD' ? decompressResponse(progressStream) : progressStream); - if (!options.decompress && ['gzip', 'deflate', 'br'].includes((_a = newResponse.headers['content-encoding'], (_a !== null && _a !== void 0 ? _a : '')))) { - options.responseType = 'buffer'; - } - emitter.emit('response', newResponse); - return pipeline(response, progressStream).catch(error => { - if (error.code !== 'ERR_STREAM_PREMATURE_CLOSE') { - throw error; - } - }); -}; - - -/***/ }), - -/***/ 278: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const is_1 = __webpack_require__(534); -exports.default = (url) => { - // Cast to URL - url = url; - const options = { - protocol: url.protocol, - hostname: is_1.default.string(url.hostname) && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, - host: url.host, - hash: url.hash, - search: url.search, - pathname: url.pathname, - href: url.href, - path: `${url.pathname || ''}${url.search || ''}` - }; - if (is_1.default.string(url.port) && url.port.length !== 0) { - options.port = Number(url.port); - } - if (url.username || url.password) { - options.auth = `${url.username || ''}:${url.password || ''}`; - } - return options; -}; - - -/***/ }), - -/***/ 291: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const is_1 = __webpack_require__(534); -function deepFreeze(object) { - for (const value of Object.values(object)) { - if (is_1.default.plainObject(value) || is_1.default.array(value)) { - deepFreeze(value); - } - } - return Object.freeze(object); + return Object.freeze(object); } exports.default = deepFreeze; @@ -2803,10 +2239,10 @@ class Keyv extends EventEmitter { } get(key, opts) { - key = this._getKeyPrefix(key); + const keyPrefixed = this._getKeyPrefix(key); const { store } = this.opts; return Promise.resolve() - .then(() => store.get(key)) + .then(() => store.get(keyPrefixed)) .then(data => { return (typeof data === 'string') ? this.opts.deserialize(data) : data; }) @@ -2825,7 +2261,7 @@ class Keyv extends EventEmitter { } set(key, value, ttl) { - key = this._getKeyPrefix(key); + const keyPrefixed = this._getKeyPrefix(key); if (typeof ttl === 'undefined') { ttl = this.opts.ttl; } @@ -2842,15 +2278,15 @@ class Keyv extends EventEmitter { value = { value, expires }; return this.opts.serialize(value); }) - .then(value => store.set(key, value, ttl)) + .then(value => store.set(keyPrefixed, value, ttl)) .then(() => true); } delete(key) { - key = this._getKeyPrefix(key); + const keyPrefixed = this._getKeyPrefix(key); const { store } = this.opts; return Promise.resolve() - .then(() => store.delete(key)); + .then(() => store.delete(keyPrefixed)); } clear() { @@ -2870,15 +2306,41 @@ module.exports = Keyv; "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); +}; Object.defineProperty(exports, "__esModule", { value: true }); +exports.defaultHandler = void 0; +const p_cancelable_1 = __webpack_require__(557); const is_1 = __webpack_require__(534); -const as_promise_1 = __webpack_require__(616); -const as_stream_1 = __webpack_require__(379); -const errors = __webpack_require__(378); -const normalize_arguments_1 = __webpack_require__(110); +const as_promise_1 = __webpack_require__(577); +const create_rejection_1 = __webpack_require__(910); +const core_1 = __webpack_require__(946); const deep_freeze_1 = __webpack_require__(291); -const getPromiseOrStream = (options) => options.isStream ? as_stream_1.default(options) : as_promise_1.default(options); -const isGotInstance = (value) => (Reflect.has(value, 'defaults') && Reflect.has(value.defaults, 'options')); +const errors = { + RequestError: as_promise_1.RequestError, + CacheError: as_promise_1.CacheError, + ReadError: as_promise_1.ReadError, + HTTPError: as_promise_1.HTTPError, + MaxRedirectsError: as_promise_1.MaxRedirectsError, + TimeoutError: as_promise_1.TimeoutError, + ParseError: as_promise_1.ParseError, + CancelError: p_cancelable_1.CancelError, + UnsupportedProtocolError: as_promise_1.UnsupportedProtocolError, + UploadError: as_promise_1.UploadError +}; +// The `delay` package weighs 10KB (!) +const delay = async (ms) => new Promise(resolve => setTimeout(resolve, ms)); +const { normalizeArguments, mergeOptions } = as_promise_1.PromisableRequest; +const getPromiseOrStream = (options) => options.isStream ? new core_1.default(options.url, options) : as_promise_1.default(options); +const isGotInstance = (value) => ('defaults' in value && 'options' in value.defaults); const aliases = [ 'get', 'post', @@ -2888,6 +2350,13 @@ const aliases = [ 'delete' ]; exports.defaultHandler = (options, next) => next(options); +const callInitHooks = (hooks, options) => { + if (hooks) { + for (const hook of hooks) { + hook(options); + } + } +}; const create = (defaults) => { // Proxy properties from next handlers defaults._rawHandlers = defaults.handlers; @@ -2911,28 +2380,50 @@ const create = (defaults) => { } return result; })); - // @ts-ignore Because the for loop handles it for us, as well as the other Object.defines - const got = (url, options) => { - var _a; + // Got interface + const got = ((url, options) => { + var _a, _b; let iteration = 0; const iterateHandlers = (newOptions) => { return defaults.handlers[iteration++](newOptions, iteration === defaults.handlers.length ? getPromiseOrStream : iterateHandlers); }; - /* eslint-disable @typescript-eslint/return-await */ + // TODO: Remove this in Got 12. + if (is_1.default.plainObject(url)) { + const mergedOptions = { + ...url, + ...options + }; + core_1.setNonEnumerableProperties([url, options], mergedOptions); + options = mergedOptions; + url = undefined; + } try { - return iterateHandlers(normalize_arguments_1.normalizeArguments(url, options, defaults)); + // Call `init` hooks + let initHookError; + try { + callInitHooks(defaults.options.hooks.init, options); + callInitHooks((_a = options === null || options === void 0 ? void 0 : options.hooks) === null || _a === void 0 ? void 0 : _a.init, options); + } + catch (error) { + initHookError = error; + } + // Normalize options & call handlers + const normalizedOptions = normalizeArguments(url, options, defaults.options); + normalizedOptions[core_1.kIsNormalizedAlready] = true; + if (initHookError) { + throw new as_promise_1.RequestError(initHookError.message, initHookError, normalizedOptions); + } + return iterateHandlers(normalizedOptions); } catch (error) { - if ((_a = options) === null || _a === void 0 ? void 0 : _a.isStream) { + if (options === null || options === void 0 ? void 0 : options.isStream) { throw error; } else { - // @ts-ignore It's an Error not a response, but TS thinks it's calling .resolve - return as_promise_1.createRejection(error); + return create_rejection_1.default(error, defaults.options.hooks.beforeError, (_b = options === null || options === void 0 ? void 0 : options.hooks) === null || _b === void 0 ? void 0 : _b.beforeError); } } - /* eslint-enable @typescript-eslint/return-await */ - }; + }); got.extend = (...instancesOrOptions) => { const optionsArray = [defaults.options]; let handlers = [...defaults._rawHandlers]; @@ -2945,7 +2436,7 @@ const create = (defaults) => { } else { optionsArray.push(value); - if (Reflect.has(value, 'handlers')) { + if ('handlers' in value) { handlers.push(...value.handlers); } isMutableDefaults = value.mutableDefaults; @@ -2956,30 +2447,33 @@ const create = (defaults) => { handlers.push(exports.defaultHandler); } return create({ - options: normalize_arguments_1.mergeOptions(...optionsArray), + options: mergeOptions(...optionsArray), handlers, mutableDefaults: Boolean(isMutableDefaults) }); }; - // @ts-ignore The missing methods because the for-loop handles it for us - got.stream = (url, options) => got(url, { ...options, isStream: true }); - for (const method of aliases) { - // @ts-ignore Cannot properly type a function with multiple definitions yet - got[method] = (url, options) => got(url, { ...options, method }); - got.stream[method] = (url, options) => got.stream(url, { ...options, method }); - } - // @ts-ignore The missing property is added below - got.paginate = async function* (url, options) { - let normalizedOptions = normalize_arguments_1.normalizeArguments(url, options, defaults); - const pagination = normalizedOptions._pagination; + // Pagination + const paginateEach = (async function* (url, options) { + // TODO: Remove this `@ts-expect-error` when upgrading to TypeScript 4. + // Error: Argument of type 'Merge> | undefined' is not assignable to parameter of type 'Options | undefined'. + // @ts-expect-error + let normalizedOptions = normalizeArguments(url, options, defaults.options); + normalizedOptions.resolveBodyOnly = false; + const pagination = normalizedOptions.pagination; if (!is_1.default.object(pagination)) { - throw new Error('`options._pagination` must be implemented'); + throw new TypeError('`options.pagination` must be implemented'); } const all = []; - while (true) { - // @ts-ignore See https://github.com/sindresorhus/got/issues/954 + let { countLimit } = pagination; + let numberOfRequests = 0; + while (numberOfRequests < pagination.requestLimit) { + if (numberOfRequests !== 0) { + // eslint-disable-next-line no-await-in-loop + await delay(pagination.backoff); + } + // TODO: Throw when result is not an instance of Response // eslint-disable-next-line no-await-in-loop - const result = await got(normalizedOptions); + const result = (await got(normalizedOptions)); // eslint-disable-next-line no-await-in-loop const parsed = await pagination.transform(result); const current = []; @@ -2989,9 +2483,11 @@ const create = (defaults) => { return; } yield item; - all.push(item); + if (pagination.stackAllItems) { + all.push(item); + } current.push(item); - if (all.length === pagination.countLimit) { + if (--countLimit <= 0) { return; } } @@ -3000,19 +2496,37 @@ const create = (defaults) => { if (optionsToMerge === false) { return; } - if (optionsToMerge !== undefined) { - normalizedOptions = normalize_arguments_1.normalizeArguments(normalizedOptions, optionsToMerge); + if (optionsToMerge === result.request.options) { + normalizedOptions = result.request.options; } + else if (optionsToMerge !== undefined) { + normalizedOptions = normalizeArguments(undefined, optionsToMerge, normalizedOptions); + } + numberOfRequests++; } - }; - got.paginate.all = async (url, options) => { + }); + got.paginate = ((url, options) => { + return paginateEach(url, options); + }); + got.paginate.all = (async (url, options) => { const results = []; for await (const item of got.paginate(url, options)) { results.push(item); } return results; - }; - Object.assign(got, { ...errors, mergeOptions: normalize_arguments_1.mergeOptions }); + }); + // For those who like very descriptive names + got.paginate.each = paginateEach; + // Stream API + got.stream = ((url, options) => got(url, { ...options, isStream: true })); + // Shortcuts + for (const method of aliases) { + got[method] = ((url, options) => got(url, { ...options, method })); + got.stream[method] = ((url, options) => { + return got(url, { ...options, method, isStream: true }); + }); + } + Object.assign(got, { ...errors, mergeOptions }); Object.defineProperty(got, 'defaults', { value: defaults.mutableDefaults ? defaults : deep_freeze_1.default(defaults), writable: defaults.mutableDefaults, @@ -3022,6 +2536,7 @@ const create = (defaults) => { return got; }; exports.default = create; +__exportStar(__webpack_require__(839), exports); /***/ }), @@ -3033,7 +2548,7 @@ exports.default = create; const PassThrough = __webpack_require__(413).PassThrough; -const mimicResponse = __webpack_require__(210); +const mimicResponse = __webpack_require__(89); const cloneResponse = response => { if (!(response && response.pipe)) { @@ -10531,337 +10046,344 @@ module.exports = options => { /***/ }), -/***/ 378: -/***/ (function(__unusedmodule, exports, __webpack_require__) { +/***/ 390: +/***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const is_1 = __webpack_require__(534); -class GotError extends Error { - constructor(message, error, options) { - super(message); - Error.captureStackTrace(this, this.constructor); - this.name = 'GotError'; - if (!is_1.default.undefined(error.code)) { - this.code = error.code; - } - Object.defineProperty(this, 'options', { - // This fails because of TS 3.7.2 useDefineForClassFields - // Ref: https://github.com/microsoft/TypeScript/issues/34972 - enumerable: false, - value: options - }); - // Recover the original stacktrace - if (!is_1.default.undefined(error.stack)) { - const indexOfMessage = this.stack.indexOf(this.message) + this.message.length; - const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse(); - const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').reverse(); - // Remove duplicated traces - while (errorStackTrace.length !== 0 && errorStackTrace[0] === thisStackTrace[0]) { - thisStackTrace.shift(); - } - this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.reverse().join('\n')}${errorStackTrace.reverse().join('\n')}`; - } - } -} -exports.GotError = GotError; -class CacheError extends GotError { - constructor(error, options) { - super(error.message, error, options); - this.name = 'CacheError'; - } -} -exports.CacheError = CacheError; -class RequestError extends GotError { - constructor(error, options) { - super(error.message, error, options); - this.name = 'RequestError'; - } -} -exports.RequestError = RequestError; -class ReadError extends GotError { - constructor(error, options) { - super(error.message, error, options); - this.name = 'ReadError'; - } -} -exports.ReadError = ReadError; -class ParseError extends GotError { - constructor(error, response, options) { - super(`${error.message} in "${options.url.toString()}"`, error, options); - this.name = 'ParseError'; - Object.defineProperty(this, 'response', { - enumerable: false, - value: response - }); - } -} -exports.ParseError = ParseError; -class HTTPError extends GotError { - constructor(response, options) { - super(`Response code ${response.statusCode} (${response.statusMessage})`, {}, options); - this.name = 'HTTPError'; - Object.defineProperty(this, 'response', { - enumerable: false, - value: response - }); - } -} -exports.HTTPError = HTTPError; -class MaxRedirectsError extends GotError { - constructor(response, maxRedirects, options) { - super(`Redirected ${maxRedirects} times. Aborting.`, {}, options); - this.name = 'MaxRedirectsError'; - Object.defineProperty(this, 'response', { - enumerable: false, - value: response - }); - } -} -exports.MaxRedirectsError = MaxRedirectsError; -class UnsupportedProtocolError extends GotError { - constructor(options) { - super(`Unsupported protocol "${options.url.protocol}"`, {}, options); - this.name = 'UnsupportedProtocolError'; - } -} -exports.UnsupportedProtocolError = UnsupportedProtocolError; -class TimeoutError extends GotError { - constructor(error, timings, options) { - super(error.message, error, options); - this.name = 'TimeoutError'; - this.event = error.event; - this.timings = timings; - } -} -exports.TimeoutError = TimeoutError; -var p_cancelable_1 = __webpack_require__(557); -exports.CancelError = p_cancelable_1.CancelError; +const EventEmitter = __webpack_require__(614); +const urlLib = __webpack_require__(835); +const normalizeUrl = __webpack_require__(53); +const getStream = __webpack_require__(997); +const CachePolicy = __webpack_require__(154); +const Response = __webpack_require__(93); +const lowercaseKeys = __webpack_require__(474); +const cloneResponse = __webpack_require__(325); +const Keyv = __webpack_require__(303); -/***/ }), +class CacheableRequest { + constructor(request, cacheAdapter) { + if (typeof request !== 'function') { + throw new TypeError('Parameter `request` must be a function'); + } -/***/ 379: -/***/ (function(__unusedmodule, exports, __webpack_require__) { + this.cache = new Keyv({ + uri: typeof cacheAdapter === 'string' && cacheAdapter, + store: typeof cacheAdapter !== 'string' && cacheAdapter, + namespace: 'cacheable-request' + }); -"use strict"; + return this.createCacheableRequest(request); + } -Object.defineProperty(exports, "__esModule", { value: true }); -const duplexer3 = __webpack_require__(718); -const http_1 = __webpack_require__(605); -const stream_1 = __webpack_require__(413); -const errors_1 = __webpack_require__(378); -const request_as_event_emitter_1 = __webpack_require__(872); -class ProxyStream extends stream_1.Duplex { -} -exports.ProxyStream = ProxyStream; -function asStream(options) { - const input = new stream_1.PassThrough(); - const output = new stream_1.PassThrough(); - const proxy = duplexer3(input, output); - const piped = new Set(); - let isFinished = false; - options.retry.calculateDelay = () => 0; - if (options.body || options.json || options.form) { - proxy.write = () => { - proxy.destroy(); - throw new Error('Got\'s stream is not writable when the `body`, `json` or `form` option is used'); - }; - } - else if (options.method === 'POST' || options.method === 'PUT' || options.method === 'PATCH' || (options.allowGetBody && options.method === 'GET')) { - options.body = input; - } - else { - proxy.write = () => { - proxy.destroy(); - throw new TypeError(`The \`${options.method}\` method cannot be used with a body`); - }; - } - const emitter = request_as_event_emitter_1.default(options); - const emitError = async (error) => { - try { - for (const hook of options.hooks.beforeError) { - // eslint-disable-next-line no-await-in-loop - error = await hook(error); - } - proxy.emit('error', error); - } - catch (error_) { - proxy.emit('error', error_); - } - }; - // Cancels the request - proxy._destroy = (error, callback) => { - callback(error); - emitter.abort(); - }; - emitter.on('response', (response) => { - const { statusCode, isFromCache } = response; - proxy.isFromCache = isFromCache; - if (options.throwHttpErrors && statusCode !== 304 && (statusCode < 200 || statusCode > 299)) { - emitError(new errors_1.HTTPError(response, options)); - return; - } - { - const read = proxy._read; - proxy._read = (...args) => { - isFinished = true; - proxy._read = read; - return read.apply(proxy, args); - }; - } - if (options.encoding) { - proxy.setEncoding(options.encoding); - } - // We cannot use `stream.pipeline(...)` here, - // because if we did then `output` would throw - // the original error before throwing `ReadError`. - response.pipe(output); - response.once('error', error => { - emitError(new errors_1.ReadError(error, options)); - }); - for (const destination of piped) { - if (destination.headersSent) { - continue; - } - for (const [key, value] of Object.entries(response.headers)) { - // Got gives *decompressed* data. Overriding `content-encoding` header would result in an error. - // It's not possible to decompress already decompressed data, is it? - const isAllowed = options.decompress ? key !== 'content-encoding' : true; - if (isAllowed) { - destination.setHeader(key, value); - } - } - destination.statusCode = response.statusCode; - } - proxy.emit('response', response); - }); - request_as_event_emitter_1.proxyEvents(proxy, emitter); - emitter.on('error', (error) => proxy.emit('error', error)); - const pipe = proxy.pipe.bind(proxy); - const unpipe = proxy.unpipe.bind(proxy); - proxy.pipe = (destination, options) => { - if (isFinished) { - throw new Error('Failed to pipe. The response has been emitted already.'); - } - pipe(destination, options); - if (destination instanceof http_1.ServerResponse) { - piped.add(destination); - } - return destination; - }; - proxy.unpipe = stream => { - piped.delete(stream); - return unpipe(stream); - }; - proxy.on('pipe', source => { - if (source instanceof http_1.IncomingMessage) { - options.headers = { - ...source.headers, - ...options.headers - }; - } - }); - proxy.isFromCache = undefined; - return proxy; -} -exports.default = asStream; + createCacheableRequest(request) { + return (opts, cb) => { + let url; + if (typeof opts === 'string') { + url = normalizeUrlObject(urlLib.parse(opts)); + opts = {}; + } else if (opts instanceof urlLib.URL) { + url = normalizeUrlObject(urlLib.parse(opts.toString())); + opts = {}; + } else { + const [pathname, ...searchParts] = (opts.path || '').split('?'); + const search = searchParts.length > 0 ? + `?${searchParts.join('?')}` : + ''; + url = normalizeUrlObject({ ...opts, pathname, search }); + } + opts = { + headers: {}, + method: 'GET', + cache: true, + strictTtl: false, + automaticFailover: false, + ...opts, + ...urlObjectToRequestOptions(url) + }; + opts.headers = lowercaseKeys(opts.headers); -/***/ }), + const ee = new EventEmitter(); + const normalizedUrlString = normalizeUrl( + urlLib.format(url), + { + stripWWW: false, + removeTrailingSlash: false, + stripAuthentication: false + } + ); + const key = `${opts.method}:${normalizedUrlString}`; + let revalidate = false; + let madeRequest = false; -/***/ 413: -/***/ (function(module) { + const makeRequest = opts => { + madeRequest = true; + let requestErrored = false; + let requestErrorCallback; -module.exports = require("stream"); + const requestErrorPromise = new Promise(resolve => { + requestErrorCallback = () => { + if (!requestErrored) { + requestErrored = true; + resolve(); + } + }; + }); -/***/ }), + const handler = response => { + if (revalidate && !opts.forceRefresh) { + response.status = response.statusCode; + const revalidatedPolicy = CachePolicy.fromObject(revalidate.cachePolicy).revalidatedPolicy(opts, response); + if (!revalidatedPolicy.modified) { + const headers = revalidatedPolicy.policy.responseHeaders(); + response = new Response(revalidate.statusCode, headers, revalidate.body, revalidate.url); + response.cachePolicy = revalidatedPolicy.policy; + response.fromCache = true; + } + } -/***/ 415: -/***/ (function(__unusedmodule, exports) { + if (!response.fromCache) { + response.cachePolicy = new CachePolicy(opts, response, opts); + response.fromCache = false; + } -"use strict"; + let clonedResponse; + if (opts.cache && response.cachePolicy.storable()) { + clonedResponse = cloneResponse(response); -/* istanbul ignore file: used for webpack */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = (moduleObject, moduleId) => moduleObject.require(moduleId); + (async () => { + try { + const bodyPromise = getStream.buffer(response); + await Promise.race([ + requestErrorPromise, + new Promise(resolve => response.once('end', resolve)) + ]); -/***/ }), + if (requestErrored) { + return; + } -/***/ 431: -/***/ (function(__unusedmodule, exports, __webpack_require__) { + const body = await bodyPromise; -"use strict"; + const value = { + cachePolicy: response.cachePolicy.toObject(), + url: response.url, + statusCode: response.fromCache ? revalidate.statusCode : response.statusCode, + body + }; -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; - result["default"] = mod; - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const os = __importStar(__webpack_require__(87)); -/** - * Commands - * - * Command Format: - * ::name key=value,key=value::message - * - * Examples: - * ::warning::This is the message - * ::set-env name=MY_VAR::some value - */ -function issueCommand(command, properties, message) { - const cmd = new Command(command, properties, message); - process.stdout.write(cmd.toString() + os.EOL); -} -exports.issueCommand = issueCommand; -function issue(name, message = '') { - issueCommand(name, {}, message); -} -exports.issue = issue; -const CMD_STRING = '::'; -class Command { - constructor(command, properties, message) { - if (!command) { - command = 'missing.command'; - } - this.command = command; - this.properties = properties; - this.message = message; - } - toString() { - let cmdStr = CMD_STRING + this.command; - if (this.properties && Object.keys(this.properties).length > 0) { - cmdStr += ' '; - let first = true; - for (const key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - const val = this.properties[key]; - if (val) { - if (first) { - first = false; - } - else { - cmdStr += ','; - } - cmdStr += `${key}=${escapeProperty(val)}`; - } - } - } - } - cmdStr += `${CMD_STRING}${escapeData(this.message)}`; - return cmdStr; - } -} -function escapeData(s) { - return (s || '') - .replace(/%/g, '%25') - .replace(/\r/g, '%0D') - .replace(/\n/g, '%0A'); + let ttl = opts.strictTtl ? response.cachePolicy.timeToLive() : undefined; + if (opts.maxTtl) { + ttl = ttl ? Math.min(ttl, opts.maxTtl) : opts.maxTtl; + } + + await this.cache.set(key, value, ttl); + } catch (error) { + ee.emit('error', new CacheableRequest.CacheError(error)); + } + })(); + } else if (opts.cache && revalidate) { + (async () => { + try { + await this.cache.delete(key); + } catch (error) { + ee.emit('error', new CacheableRequest.CacheError(error)); + } + })(); + } + + ee.emit('response', clonedResponse || response); + if (typeof cb === 'function') { + cb(clonedResponse || response); + } + }; + + try { + const req = request(opts, handler); + req.once('error', requestErrorCallback); + req.once('abort', requestErrorCallback); + ee.emit('request', req); + } catch (error) { + ee.emit('error', new CacheableRequest.RequestError(error)); + } + }; + + (async () => { + const get = async opts => { + await Promise.resolve(); + + const cacheEntry = opts.cache ? await this.cache.get(key) : undefined; + if (typeof cacheEntry === 'undefined') { + return makeRequest(opts); + } + + const policy = CachePolicy.fromObject(cacheEntry.cachePolicy); + if (policy.satisfiesWithoutRevalidation(opts) && !opts.forceRefresh) { + const headers = policy.responseHeaders(); + const response = new Response(cacheEntry.statusCode, headers, cacheEntry.body, cacheEntry.url); + response.cachePolicy = policy; + response.fromCache = true; + + ee.emit('response', response); + if (typeof cb === 'function') { + cb(response); + } + } else { + revalidate = cacheEntry; + opts.headers = policy.revalidationHeaders(opts); + makeRequest(opts); + } + }; + + const errorHandler = error => ee.emit('error', new CacheableRequest.CacheError(error)); + this.cache.once('error', errorHandler); + ee.on('response', () => this.cache.removeListener('error', errorHandler)); + + try { + await get(opts); + } catch (error) { + if (opts.automaticFailover && !madeRequest) { + makeRequest(opts); + } + + ee.emit('error', new CacheableRequest.CacheError(error)); + } + })(); + + return ee; + }; + } +} + +function urlObjectToRequestOptions(url) { + const options = { ...url }; + options.path = `${url.pathname || '/'}${url.search || ''}`; + delete options.pathname; + delete options.search; + return options; +} + +function normalizeUrlObject(url) { + // If url was parsed by url.parse or new URL: + // - hostname will be set + // - host will be hostname[:port] + // - port will be set if it was explicit in the parsed string + // Otherwise, url was from request options: + // - hostname or host may be set + // - host shall not have port encoded + return { + protocol: url.protocol, + auth: url.auth, + hostname: url.hostname || url.host || 'localhost', + port: url.port, + pathname: url.pathname, + search: url.search + }; +} + +CacheableRequest.RequestError = class extends Error { + constructor(error) { + super(error.message); + this.name = 'RequestError'; + Object.assign(this, error); + } +}; + +CacheableRequest.CacheError = class extends Error { + constructor(error) { + super(error.message); + this.name = 'CacheError'; + Object.assign(this, error); + } +}; + +module.exports = CacheableRequest; + + +/***/ }), + +/***/ 413: +/***/ (function(module) { + +module.exports = require("stream"); + +/***/ }), + +/***/ 431: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const os = __importStar(__webpack_require__(87)); +/** + * Commands + * + * Command Format: + * ::name key=value,key=value::message + * + * Examples: + * ::warning::This is the message + * ::set-env name=MY_VAR::some value + */ +function issueCommand(command, properties, message) { + const cmd = new Command(command, properties, message); + process.stdout.write(cmd.toString() + os.EOL); +} +exports.issueCommand = issueCommand; +function issue(name, message = '') { + issueCommand(name, {}, message); +} +exports.issue = issue; +const CMD_STRING = '::'; +class Command { + constructor(command, properties, message) { + if (!command) { + command = 'missing.command'; + } + this.command = command; + this.properties = properties; + this.message = message; + } + toString() { + let cmdStr = CMD_STRING + this.command; + if (this.properties && Object.keys(this.properties).length > 0) { + cmdStr += ' '; + let first = true; + for (const key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + const val = this.properties[key]; + if (val) { + if (first) { + first = false; + } + else { + cmdStr += ','; + } + cmdStr += `${key}=${escapeProperty(val)}`; + } + } + } + } + cmdStr += `${CMD_STRING}${escapeData(this.message)}`; + return cmdStr; + } +} +function escapeData(s) { + return (s || '') + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A'); } function escapeProperty(s) { return (s || '') @@ -10873,6 +10395,30 @@ function escapeProperty(s) { } //# sourceMappingURL=command.js.map +/***/ }), + +/***/ 452: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +// TODO: Update https://github.com/sindresorhus/get-stream +const getBuffer = async (stream) => { + const chunks = []; + let length = 0; + for await (const chunk of stream) { + chunks.push(chunk); + length += Buffer.byteLength(chunk); + } + if (Buffer.isBuffer(chunks[0])) { + return Buffer.concat(chunks, length); + } + return Buffer.from(chunks.join('')); +}; +exports.default = getBuffer; + + /***/ }), /***/ 453: @@ -10962,6 +10508,18 @@ var pump = function () { module.exports = pump +/***/ }), + +/***/ 460: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const is_1 = __webpack_require__(534); +exports.default = (body) => is_1.default.nodeStream(body) && is_1.default.function_(body.getBoundary); + + /***/ }), /***/ 461: @@ -11046,37 +10604,172 @@ module.exports = { /***/ }), -/***/ 470: +/***/ 468: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; - result["default"] = mod; - return result; -}; Object.defineProperty(exports, "__esModule", { value: true }); -const command_1 = __webpack_require__(431); -const os = __importStar(__webpack_require__(87)); -const path = __importStar(__webpack_require__(622)); -/** - * The code to exit an action - */ -var ExitCode; -(function (ExitCode) { - /** +exports.parseBody = exports.knownBodyTypes = void 0; +const is_1 = __webpack_require__(534); +const types_1 = __webpack_require__(36); +const core_1 = __webpack_require__(946); +if (!core_1.knownHookEvents.includes('beforeRetry')) { + core_1.knownHookEvents.push('beforeRetry', 'afterResponse'); +} +exports.knownBodyTypes = ['json', 'buffer', 'text']; +exports.parseBody = (response, responseType, parseJson, encoding) => { + const { rawBody } = response; + try { + if (responseType === 'text') { + return rawBody.toString(encoding); + } + if (responseType === 'json') { + return rawBody.length === 0 ? '' : parseJson(rawBody.toString()); + } + if (responseType === 'buffer') { + return Buffer.from(rawBody); + } + throw new types_1.ParseError({ + message: `Unknown body type '${responseType}'`, + name: 'Error' + }, response); + } + catch (error) { + throw new types_1.ParseError(error, response); + } +}; +class PromisableRequest extends core_1.default { + static normalizeArguments(url, nonNormalizedOptions, defaults) { + const options = super.normalizeArguments(url, nonNormalizedOptions, defaults); + if (is_1.default.null_(options.encoding)) { + throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead'); + } + is_1.assert.any([is_1.default.string, is_1.default.undefined], options.encoding); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.resolveBodyOnly); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.methodRewriting); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.isStream); + is_1.assert.any([is_1.default.string, is_1.default.undefined], options.responseType); + // `options.responseType` + if (options.responseType === undefined) { + options.responseType = 'text'; + } + // `options.retry` + const { retry } = options; + if (defaults) { + options.retry = { ...defaults.retry }; + } + else { + options.retry = { + calculateDelay: retryObject => retryObject.computedValue, + limit: 0, + methods: [], + statusCodes: [], + errorCodes: [], + maxRetryAfter: undefined + }; + } + if (is_1.default.object(retry)) { + options.retry = { + ...options.retry, + ...retry + }; + options.retry.methods = [...new Set(options.retry.methods.map(method => method.toUpperCase()))]; + options.retry.statusCodes = [...new Set(options.retry.statusCodes)]; + options.retry.errorCodes = [...new Set(options.retry.errorCodes)]; + } + else if (is_1.default.number(retry)) { + options.retry.limit = retry; + } + if (is_1.default.undefined(options.retry.maxRetryAfter)) { + options.retry.maxRetryAfter = Math.min( + // TypeScript is not smart enough to handle `.filter(x => is.number(x))`. + // eslint-disable-next-line unicorn/no-fn-reference-in-iterator + ...[options.timeout.request, options.timeout.connect].filter(is_1.default.number)); + } + // `options.pagination` + if (is_1.default.object(options.pagination)) { + if (defaults) { + options.pagination = { + ...defaults.pagination, + ...options.pagination + }; + } + const { pagination } = options; + if (!is_1.default.function_(pagination.transform)) { + throw new Error('`options.pagination.transform` must be implemented'); + } + if (!is_1.default.function_(pagination.shouldContinue)) { + throw new Error('`options.pagination.shouldContinue` must be implemented'); + } + if (!is_1.default.function_(pagination.filter)) { + throw new TypeError('`options.pagination.filter` must be implemented'); + } + if (!is_1.default.function_(pagination.paginate)) { + throw new Error('`options.pagination.paginate` must be implemented'); + } + } + // JSON mode + if (options.responseType === 'json' && options.headers.accept === undefined) { + options.headers.accept = 'application/json'; + } + return options; + } + static mergeOptions(...sources) { + let mergedOptions; + for (const source of sources) { + mergedOptions = PromisableRequest.normalizeArguments(undefined, source, mergedOptions); + } + return mergedOptions; + } + _beforeError(error) { + if (this.destroyed) { + return; + } + if (!(error instanceof core_1.RequestError)) { + error = new core_1.RequestError(error.message, error, this); + } + // Let the promise decide whether to abort or not + // It is also responsible for the `beforeError` hook + this.emit('error', error); + } +} +exports.default = PromisableRequest; + + +/***/ }), + +/***/ 470: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const command_1 = __webpack_require__(431); +const os = __importStar(__webpack_require__(87)); +const path = __importStar(__webpack_require__(622)); +/** + * The code to exit an action + */ +var ExitCode; +(function (ExitCode) { + /** * A code indicating that the action was successful */ ExitCode[ExitCode["Success"] = 0] = "Success"; @@ -11278,54 +10971,6 @@ module.exports = object => { }; -/***/ }), - -/***/ 489: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(413); -const is_1 = __webpack_require__(534); -function createProgressStream(name, emitter, totalBytes) { - let transformedBytes = 0; - if (is_1.default.string(totalBytes)) { - totalBytes = Number(totalBytes); - } - const progressStream = new stream_1.Transform({ - transform(chunk, _encoding, callback) { - transformedBytes += chunk.length; - const percent = totalBytes ? transformedBytes / totalBytes : 0; - // Let `flush()` be responsible for emitting the last event - if (percent < 1) { - emitter.emit(name, { - percent, - transferred: transformedBytes, - total: totalBytes - }); - } - callback(undefined, chunk); - }, - flush(callback) { - emitter.emit(name, { - percent: 1, - transferred: transformedBytes, - total: totalBytes - }); - callback(); - } - }); - emitter.emit(name, { - percent: 0, - transferred: 0, - total: totalBytes - }); - return progressStream; -} -exports.createProgressStream = createProgressStream; - - /***/ }), /***/ 490: @@ -11461,12 +11106,70 @@ const { exportSecrets } = __webpack_require__(928); (async () => { try { - await core.group('Get Vault Secrets', exportSecrets); + await core.group('Test Get Vault Secrets', exportSecrets); } catch (error) { core.setFailed(error.message); } })(); + +/***/ }), + +/***/ 507: +/***/ (function(module) { + +"use strict"; + +/* istanbul ignore file: https://github.com/nodejs/node/blob/a91293d4d9ab403046ab5eb022332e4e3d249bd3/lib/internal/url.js#L1257 */ + +module.exports = url => { + const options = { + protocol: url.protocol, + hostname: typeof url.hostname === 'string' && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, + host: url.host, + hash: url.hash, + search: url.search, + pathname: url.pathname, + href: url.href, + path: `${url.pathname || ''}${url.search || ''}` + }; + + if (typeof url.port === 'string' && url.port.length !== 0) { + options.port = Number(url.port); + } + + if (url.username || url.password) { + options.auth = `${url.username || ''}:${url.password || ''}`; + } + + return options; +}; + + +/***/ }), + +/***/ 524: +/***/ (function(module, __unusedexports, __webpack_require__) { + +"use strict"; + +const tls = __webpack_require__(16); + +module.exports = (options = {}) => new Promise((resolve, reject) => { + const socket = tls.connect(options, () => { + if (options.resolveSocket) { + socket.off('error', reject); + resolve({alpnProtocol: socket.alpnProtocol, socket}); + } else { + socket.destroy(); + resolve({alpnProtocol: socket.alpnProtocol}); + } + }); + + socket.on('error', reject); +}); + + /***/ }), /***/ 534: @@ -11478,49 +11181,108 @@ const { exportSecrets } = __webpack_require__(928); /// /// Object.defineProperty(exports, "__esModule", { value: true }); +const typedArrayTypeNames = [ + 'Int8Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array', + 'BigInt64Array', + 'BigUint64Array' +]; +function isTypedArrayName(name) { + return typedArrayTypeNames.includes(name); +} +const objectTypeNames = [ + 'Function', + 'Generator', + 'AsyncGenerator', + 'GeneratorFunction', + 'AsyncGeneratorFunction', + 'AsyncFunction', + 'Observable', + 'Array', + 'Buffer', + 'Object', + 'RegExp', + 'Date', + 'Error', + 'Map', + 'Set', + 'WeakMap', + 'WeakSet', + 'ArrayBuffer', + 'SharedArrayBuffer', + 'DataView', + 'Promise', + 'URL', + 'HTMLElement', + ...typedArrayTypeNames +]; +function isObjectTypeName(name) { + return objectTypeNames.includes(name); +} +const primitiveTypeNames = [ + 'null', + 'undefined', + 'string', + 'number', + 'bigint', + 'boolean', + 'symbol' +]; +function isPrimitiveTypeName(name) { + return primitiveTypeNames.includes(name); +} +// eslint-disable-next-line @typescript-eslint/ban-types +function isOfType(type) { + return (value) => typeof value === type; +} const { toString } = Object.prototype; -const isOfType = (type) => (value) => typeof value === type; const getObjectType = (value) => { - const objectName = toString.call(value).slice(8, -1); - if (objectName) { - return objectName; + const objectTypeName = toString.call(value).slice(8, -1); + if (/HTML\w+Element/.test(objectTypeName) && is.domElement(value)) { + return 'HTMLElement'; + } + if (isObjectTypeName(objectTypeName)) { + return objectTypeName; } return undefined; }; const isObjectOfType = (type) => (value) => getObjectType(value) === type; function is(value) { - switch (value) { - case null: - return "null" /* null */; - case true: - case false: - return "boolean" /* boolean */; - default: + if (value === null) { + return 'null'; } switch (typeof value) { case 'undefined': - return "undefined" /* undefined */; + return 'undefined'; case 'string': - return "string" /* string */; + return 'string'; case 'number': - return "number" /* number */; + return 'number'; + case 'boolean': + return 'boolean'; + case 'function': + return 'Function'; case 'bigint': - return "bigint" /* bigint */; + return 'bigint'; case 'symbol': - return "symbol" /* symbol */; + return 'symbol'; default: } - if (is.function_(value)) { - return "Function" /* Function */; - } if (is.observable(value)) { - return "Observable" /* Observable */; + return 'Observable'; } if (is.array(value)) { - return "Array" /* Array */; + return 'Array'; } if (is.buffer(value)) { - return "Buffer" /* Buffer */; + return 'Buffer'; } const tagType = getObjectType(value); if (tagType) { @@ -11529,7 +11291,7 @@ function is(value) { if (value instanceof String || value instanceof Boolean || value instanceof Number) { throw new TypeError('Please don\'t use object wrappers for primitive types'); } - return "Object" /* Object */; + return 'Object'; } is.undefined = isOfType('undefined'); is.string = isOfType('string'); @@ -11542,48 +11304,58 @@ is.null_ = (value) => value === null; is.class_ = (value) => is.function_(value) && value.toString().startsWith('class '); is.boolean = (value) => value === true || value === false; is.symbol = isOfType('symbol'); -is.numericString = (value) => is.string(value) && value.length > 0 && !Number.isNaN(Number(value)); -is.array = Array.isArray; -is.buffer = (value) => !is.nullOrUndefined(value) && !is.nullOrUndefined(value.constructor) && is.function_(value.constructor.isBuffer) && value.constructor.isBuffer(value); +is.numericString = (value) => is.string(value) && !is.emptyStringOrWhitespace(value) && !Number.isNaN(Number(value)); +is.array = (value, assertion) => { + if (!Array.isArray(value)) { + return false; + } + if (!assertion) { + return true; + } + return value.every(assertion); +}; +is.buffer = (value) => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = value) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.isBuffer) === null || _c === void 0 ? void 0 : _c.call(_b, value)) !== null && _d !== void 0 ? _d : false; }; is.nullOrUndefined = (value) => is.null_(value) || is.undefined(value); is.object = (value) => !is.null_(value) && (typeof value === 'object' || is.function_(value)); -is.iterable = (value) => !is.nullOrUndefined(value) && is.function_(value[Symbol.iterator]); -is.asyncIterable = (value) => !is.nullOrUndefined(value) && is.function_(value[Symbol.asyncIterator]); +is.iterable = (value) => { var _a; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a[Symbol.iterator]); }; +is.asyncIterable = (value) => { var _a; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a[Symbol.asyncIterator]); }; is.generator = (value) => is.iterable(value) && is.function_(value.next) && is.function_(value.throw); is.asyncGenerator = (value) => is.asyncIterable(value) && is.function_(value.next) && is.function_(value.throw); -is.nativePromise = (value) => isObjectOfType("Promise" /* Promise */)(value); -const hasPromiseAPI = (value) => is.object(value) && - is.function_(value.then) && // eslint-disable-line promise/prefer-await-to-then - is.function_(value.catch); +is.nativePromise = (value) => isObjectOfType('Promise')(value); +const hasPromiseAPI = (value) => { + var _a, _b; + return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a.then) && + is.function_((_b = value) === null || _b === void 0 ? void 0 : _b.catch); +}; is.promise = (value) => is.nativePromise(value) || hasPromiseAPI(value); -is.generatorFunction = isObjectOfType("GeneratorFunction" /* GeneratorFunction */); -is.asyncGeneratorFunction = (value) => getObjectType(value) === "AsyncGeneratorFunction" /* AsyncGeneratorFunction */; -is.asyncFunction = (value) => getObjectType(value) === "AsyncFunction" /* AsyncFunction */; +is.generatorFunction = isObjectOfType('GeneratorFunction'); +is.asyncGeneratorFunction = (value) => getObjectType(value) === 'AsyncGeneratorFunction'; +is.asyncFunction = (value) => getObjectType(value) === 'AsyncFunction'; // eslint-disable-next-line no-prototype-builtins, @typescript-eslint/ban-types is.boundFunction = (value) => is.function_(value) && !value.hasOwnProperty('prototype'); -is.regExp = isObjectOfType("RegExp" /* RegExp */); -is.date = isObjectOfType("Date" /* Date */); -is.error = isObjectOfType("Error" /* Error */); -is.map = (value) => isObjectOfType("Map" /* Map */)(value); -is.set = (value) => isObjectOfType("Set" /* Set */)(value); -is.weakMap = (value) => isObjectOfType("WeakMap" /* WeakMap */)(value); -is.weakSet = (value) => isObjectOfType("WeakSet" /* WeakSet */)(value); -is.int8Array = isObjectOfType("Int8Array" /* Int8Array */); -is.uint8Array = isObjectOfType("Uint8Array" /* Uint8Array */); -is.uint8ClampedArray = isObjectOfType("Uint8ClampedArray" /* Uint8ClampedArray */); -is.int16Array = isObjectOfType("Int16Array" /* Int16Array */); -is.uint16Array = isObjectOfType("Uint16Array" /* Uint16Array */); -is.int32Array = isObjectOfType("Int32Array" /* Int32Array */); -is.uint32Array = isObjectOfType("Uint32Array" /* Uint32Array */); -is.float32Array = isObjectOfType("Float32Array" /* Float32Array */); -is.float64Array = isObjectOfType("Float64Array" /* Float64Array */); -is.bigInt64Array = isObjectOfType("BigInt64Array" /* BigInt64Array */); -is.bigUint64Array = isObjectOfType("BigUint64Array" /* BigUint64Array */); -is.arrayBuffer = isObjectOfType("ArrayBuffer" /* ArrayBuffer */); -is.sharedArrayBuffer = isObjectOfType("SharedArrayBuffer" /* SharedArrayBuffer */); -is.dataView = isObjectOfType("DataView" /* DataView */); +is.regExp = isObjectOfType('RegExp'); +is.date = isObjectOfType('Date'); +is.error = isObjectOfType('Error'); +is.map = (value) => isObjectOfType('Map')(value); +is.set = (value) => isObjectOfType('Set')(value); +is.weakMap = (value) => isObjectOfType('WeakMap')(value); +is.weakSet = (value) => isObjectOfType('WeakSet')(value); +is.int8Array = isObjectOfType('Int8Array'); +is.uint8Array = isObjectOfType('Uint8Array'); +is.uint8ClampedArray = isObjectOfType('Uint8ClampedArray'); +is.int16Array = isObjectOfType('Int16Array'); +is.uint16Array = isObjectOfType('Uint16Array'); +is.int32Array = isObjectOfType('Int32Array'); +is.uint32Array = isObjectOfType('Uint32Array'); +is.float32Array = isObjectOfType('Float32Array'); +is.float64Array = isObjectOfType('Float64Array'); +is.bigInt64Array = isObjectOfType('BigInt64Array'); +is.bigUint64Array = isObjectOfType('BigUint64Array'); +is.arrayBuffer = isObjectOfType('ArrayBuffer'); +is.sharedArrayBuffer = isObjectOfType('SharedArrayBuffer'); +is.dataView = isObjectOfType('DataView'); is.directInstanceOf = (instance, class_) => Object.getPrototypeOf(instance) === class_.prototype; -is.urlInstance = (value) => isObjectOfType("URL" /* URL */)(value); +is.urlInstance = (value) => isObjectOfType('URL')(value); is.urlString = (value) => { if (!is.string(value)) { return false; @@ -11602,45 +11374,18 @@ is.truthy = (value) => Boolean(value); // Example: `is.falsy = (value: unknown): value is (not true | 0 | '' | undefined | null) => Boolean(value);` is.falsy = (value) => !value; is.nan = (value) => Number.isNaN(value); -const primitiveTypeOfTypes = new Set([ - 'undefined', - 'string', - 'number', - 'bigint', - 'boolean', - 'symbol' -]); -is.primitive = (value) => is.null_(value) || primitiveTypeOfTypes.has(typeof value); +is.primitive = (value) => is.null_(value) || isPrimitiveTypeName(typeof value); is.integer = (value) => Number.isInteger(value); is.safeInteger = (value) => Number.isSafeInteger(value); is.plainObject = (value) => { // From: https://github.com/sindresorhus/is-plain-obj/blob/master/index.js - if (getObjectType(value) !== "Object" /* Object */) { + if (toString.call(value) !== '[object Object]') { return false; } const prototype = Object.getPrototypeOf(value); return prototype === null || prototype === Object.getPrototypeOf({}); }; -const typedArrayTypes = new Set([ - "Int8Array" /* Int8Array */, - "Uint8Array" /* Uint8Array */, - "Uint8ClampedArray" /* Uint8ClampedArray */, - "Int16Array" /* Int16Array */, - "Uint16Array" /* Uint16Array */, - "Int32Array" /* Int32Array */, - "Uint32Array" /* Uint32Array */, - "Float32Array" /* Float32Array */, - "Float64Array" /* Float64Array */, - "BigInt64Array" /* BigInt64Array */, - "BigUint64Array" /* BigUint64Array */ -]); -is.typedArray = (value) => { - const objectType = getObjectType(value); - if (objectType === undefined) { - return false; - } - return typedArrayTypes.has(objectType); -}; +is.typedArray = (value) => isTypedArrayName(getObjectType(value)); const isValidLength = (value) => is.safeInteger(value) && value >= 0; is.arrayLike = (value) => !is.nullOrUndefined(value) && !is.function_(value) && isValidLength(value.length); is.inRange = (value, range) => { @@ -11660,17 +11405,23 @@ const DOM_PROPERTIES_TO_CHECK = [ 'attributes', 'nodeValue' ]; -is.domElement = (value) => is.object(value) && value.nodeType === NODE_TYPE_ELEMENT && is.string(value.nodeName) && - !is.plainObject(value) && DOM_PROPERTIES_TO_CHECK.every(property => property in value); +is.domElement = (value) => { + return is.object(value) && + value.nodeType === NODE_TYPE_ELEMENT && + is.string(value.nodeName) && + !is.plainObject(value) && + DOM_PROPERTIES_TO_CHECK.every(property => property in value); +}; is.observable = (value) => { + var _a, _b, _c, _d; if (!value) { return false; } // eslint-disable-next-line no-use-extend-native/no-use-extend-native - if (value[Symbol.observable] && value === value[Symbol.observable]()) { + if (value === ((_b = (_a = value)[Symbol.observable]) === null || _b === void 0 ? void 0 : _b.call(_a))) { return true; } - if (value['@@observable'] && value === value['@@observable']()) { + if (value === ((_d = (_c = value)['@@observable']) === null || _d === void 0 ? void 0 : _d.call(_c))) { return true; } return false; @@ -11685,7 +11436,7 @@ is.nonEmptyArray = (value) => is.array(value) && value.length > 0; is.emptyString = (value) => is.string(value) && value.length === 0; // TODO: Use `not ''` when the `not` operator is available. is.nonEmptyString = (value) => is.string(value) && value.length > 0; -const isWhiteSpaceString = (value) => is.string(value) && /\S/.test(value) === false; +const isWhiteSpaceString = (value) => is.string(value) && !/\S/.test(value); is.emptyStringOrWhitespace = (value) => is.emptyString(value) || isWhiteSpaceString(value); is.emptyObject = (value) => is.object(value) && !is.map(value) && !is.set(value) && Object.keys(value).length === 0; // TODO: Use `not` operator here to remove `Map` and `Set` from type guard: @@ -11696,7 +11447,7 @@ is.nonEmptySet = (value) => is.set(value) && value.size > 0; is.emptyMap = (value) => is.map(value) && value.size === 0; is.nonEmptyMap = (value) => is.map(value) && value.size > 0; const predicateOnArray = (method, predicate, values) => { - if (is.function_(predicate) === false) { + if (!is.function_(predicate)) { throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`); } if (values.length === 0) { @@ -11716,55 +11467,61 @@ const assertType = (condition, description, value) => { }; exports.assert = { // Unknowns. - undefined: (value) => assertType(is.undefined(value), "undefined" /* undefined */, value), - string: (value) => assertType(is.string(value), "string" /* string */, value), - number: (value) => assertType(is.number(value), "number" /* number */, value), - bigint: (value) => assertType(is.bigint(value), "bigint" /* bigint */, value), + undefined: (value) => assertType(is.undefined(value), 'undefined', value), + string: (value) => assertType(is.string(value), 'string', value), + number: (value) => assertType(is.number(value), 'number', value), + bigint: (value) => assertType(is.bigint(value), 'bigint', value), // eslint-disable-next-line @typescript-eslint/ban-types - function_: (value) => assertType(is.function_(value), "Function" /* Function */, value), - null_: (value) => assertType(is.null_(value), "null" /* null */, value), + function_: (value) => assertType(is.function_(value), 'Function', value), + null_: (value) => assertType(is.null_(value), 'null', value), class_: (value) => assertType(is.class_(value), "Class" /* class_ */, value), - boolean: (value) => assertType(is.boolean(value), "boolean" /* boolean */, value), - symbol: (value) => assertType(is.symbol(value), "symbol" /* symbol */, value), + boolean: (value) => assertType(is.boolean(value), 'boolean', value), + symbol: (value) => assertType(is.symbol(value), 'symbol', value), numericString: (value) => assertType(is.numericString(value), "string with a number" /* numericString */, value), - array: (value) => assertType(is.array(value), "Array" /* Array */, value), - buffer: (value) => assertType(is.buffer(value), "Buffer" /* Buffer */, value), + array: (value, assertion) => { + const assert = assertType; + assert(is.array(value), 'Array', value); + if (assertion) { + value.forEach(assertion); + } + }, + buffer: (value) => assertType(is.buffer(value), 'Buffer', value), nullOrUndefined: (value) => assertType(is.nullOrUndefined(value), "null or undefined" /* nullOrUndefined */, value), - object: (value) => assertType(is.object(value), "Object" /* Object */, value), + object: (value) => assertType(is.object(value), 'Object', value), iterable: (value) => assertType(is.iterable(value), "Iterable" /* iterable */, value), asyncIterable: (value) => assertType(is.asyncIterable(value), "AsyncIterable" /* asyncIterable */, value), - generator: (value) => assertType(is.generator(value), "Generator" /* Generator */, value), - asyncGenerator: (value) => assertType(is.asyncGenerator(value), "AsyncGenerator" /* AsyncGenerator */, value), + generator: (value) => assertType(is.generator(value), 'Generator', value), + asyncGenerator: (value) => assertType(is.asyncGenerator(value), 'AsyncGenerator', value), nativePromise: (value) => assertType(is.nativePromise(value), "native Promise" /* nativePromise */, value), - promise: (value) => assertType(is.promise(value), "Promise" /* Promise */, value), - generatorFunction: (value) => assertType(is.generatorFunction(value), "GeneratorFunction" /* GeneratorFunction */, value), - asyncGeneratorFunction: (value) => assertType(is.asyncGeneratorFunction(value), "AsyncGeneratorFunction" /* AsyncGeneratorFunction */, value), + promise: (value) => assertType(is.promise(value), 'Promise', value), + generatorFunction: (value) => assertType(is.generatorFunction(value), 'GeneratorFunction', value), + asyncGeneratorFunction: (value) => assertType(is.asyncGeneratorFunction(value), 'AsyncGeneratorFunction', value), // eslint-disable-next-line @typescript-eslint/ban-types - asyncFunction: (value) => assertType(is.asyncFunction(value), "AsyncFunction" /* AsyncFunction */, value), + asyncFunction: (value) => assertType(is.asyncFunction(value), 'AsyncFunction', value), // eslint-disable-next-line @typescript-eslint/ban-types - boundFunction: (value) => assertType(is.boundFunction(value), "Function" /* Function */, value), - regExp: (value) => assertType(is.regExp(value), "RegExp" /* RegExp */, value), - date: (value) => assertType(is.date(value), "Date" /* Date */, value), - error: (value) => assertType(is.error(value), "Error" /* Error */, value), - map: (value) => assertType(is.map(value), "Map" /* Map */, value), - set: (value) => assertType(is.set(value), "Set" /* Set */, value), - weakMap: (value) => assertType(is.weakMap(value), "WeakMap" /* WeakMap */, value), - weakSet: (value) => assertType(is.weakSet(value), "WeakSet" /* WeakSet */, value), - int8Array: (value) => assertType(is.int8Array(value), "Int8Array" /* Int8Array */, value), - uint8Array: (value) => assertType(is.uint8Array(value), "Uint8Array" /* Uint8Array */, value), - uint8ClampedArray: (value) => assertType(is.uint8ClampedArray(value), "Uint8ClampedArray" /* Uint8ClampedArray */, value), - int16Array: (value) => assertType(is.int16Array(value), "Int16Array" /* Int16Array */, value), - uint16Array: (value) => assertType(is.uint16Array(value), "Uint16Array" /* Uint16Array */, value), - int32Array: (value) => assertType(is.int32Array(value), "Int32Array" /* Int32Array */, value), - uint32Array: (value) => assertType(is.uint32Array(value), "Uint32Array" /* Uint32Array */, value), - float32Array: (value) => assertType(is.float32Array(value), "Float32Array" /* Float32Array */, value), - float64Array: (value) => assertType(is.float64Array(value), "Float64Array" /* Float64Array */, value), - bigInt64Array: (value) => assertType(is.bigInt64Array(value), "BigInt64Array" /* BigInt64Array */, value), - bigUint64Array: (value) => assertType(is.bigUint64Array(value), "BigUint64Array" /* BigUint64Array */, value), - arrayBuffer: (value) => assertType(is.arrayBuffer(value), "ArrayBuffer" /* ArrayBuffer */, value), - sharedArrayBuffer: (value) => assertType(is.sharedArrayBuffer(value), "SharedArrayBuffer" /* SharedArrayBuffer */, value), - dataView: (value) => assertType(is.dataView(value), "DataView" /* DataView */, value), - urlInstance: (value) => assertType(is.urlInstance(value), "URL" /* URL */, value), + boundFunction: (value) => assertType(is.boundFunction(value), 'Function', value), + regExp: (value) => assertType(is.regExp(value), 'RegExp', value), + date: (value) => assertType(is.date(value), 'Date', value), + error: (value) => assertType(is.error(value), 'Error', value), + map: (value) => assertType(is.map(value), 'Map', value), + set: (value) => assertType(is.set(value), 'Set', value), + weakMap: (value) => assertType(is.weakMap(value), 'WeakMap', value), + weakSet: (value) => assertType(is.weakSet(value), 'WeakSet', value), + int8Array: (value) => assertType(is.int8Array(value), 'Int8Array', value), + uint8Array: (value) => assertType(is.uint8Array(value), 'Uint8Array', value), + uint8ClampedArray: (value) => assertType(is.uint8ClampedArray(value), 'Uint8ClampedArray', value), + int16Array: (value) => assertType(is.int16Array(value), 'Int16Array', value), + uint16Array: (value) => assertType(is.uint16Array(value), 'Uint16Array', value), + int32Array: (value) => assertType(is.int32Array(value), 'Int32Array', value), + uint32Array: (value) => assertType(is.uint32Array(value), 'Uint32Array', value), + float32Array: (value) => assertType(is.float32Array(value), 'Float32Array', value), + float64Array: (value) => assertType(is.float64Array(value), 'Float64Array', value), + bigInt64Array: (value) => assertType(is.bigInt64Array(value), 'BigInt64Array', value), + bigUint64Array: (value) => assertType(is.bigUint64Array(value), 'BigUint64Array', value), + arrayBuffer: (value) => assertType(is.arrayBuffer(value), 'ArrayBuffer', value), + sharedArrayBuffer: (value) => assertType(is.sharedArrayBuffer(value), 'SharedArrayBuffer', value), + dataView: (value) => assertType(is.dataView(value), 'DataView', value), + urlInstance: (value) => assertType(is.urlInstance(value), 'URL', value), urlString: (value) => assertType(is.urlString(value), "string with a URL" /* urlString */, value), truthy: (value) => assertType(is.truthy(value), "truthy" /* truthy */, value), falsy: (value) => assertType(is.falsy(value), "falsy" /* falsy */, value), @@ -11775,8 +11532,8 @@ exports.assert = { plainObject: (value) => assertType(is.plainObject(value), "plain object" /* plainObject */, value), typedArray: (value) => assertType(is.typedArray(value), "TypedArray" /* typedArray */, value), arrayLike: (value) => assertType(is.arrayLike(value), "array-like" /* arrayLike */, value), - domElement: (value) => assertType(is.domElement(value), "Element" /* domElement */, value), - observable: (value) => assertType(is.observable(value), "Observable" /* Observable */, value), + domElement: (value) => assertType(is.domElement(value), "HTMLElement" /* domElement */, value), + observable: (value) => assertType(is.observable(value), 'Observable', value), nodeStream: (value) => assertType(is.nodeStream(value), "Node.js Stream" /* nodeStream */, value), infinite: (value) => assertType(is.infinite(value), "infinite number" /* infinite */, value), emptyArray: (value) => assertType(is.emptyArray(value), "empty array" /* emptyArray */, value), @@ -11823,1938 +11580,4256 @@ Object.defineProperties(exports.assert, { null: { value: exports.assert.null_ } -}); -exports.default = is; -// For CommonJS default export support -module.exports = is; -module.exports.default = is; -module.exports.assert = exports.assert; +}); +exports.default = is; +// For CommonJS default export support +module.exports = is; +module.exports.default = is; +module.exports.assert = exports.assert; + + +/***/ }), + +/***/ 537: +/***/ (function(module) { + +"use strict"; + + +// We define these manually to ensure they're always copied +// even if they would move up the prototype chain +// https://nodejs.org/api/http.html#http_class_http_incomingmessage +const knownProperties = [ + 'aborted', + 'complete', + 'headers', + 'httpVersion', + 'httpVersionMinor', + 'httpVersionMajor', + 'method', + 'rawHeaders', + 'rawTrailers', + 'setTimeout', + 'socket', + 'statusCode', + 'statusMessage', + 'trailers', + 'url' +]; + +module.exports = (fromStream, toStream) => { + if (toStream._readableState.autoDestroy) { + throw new Error('The second stream must have the `autoDestroy` option set to `false`'); + } + + const fromProperties = new Set(Object.keys(fromStream).concat(knownProperties)); + + const properties = {}; + + for (const property of fromProperties) { + // Don't overwrite existing properties. + if (property in toStream) { + continue; + } + + properties[property] = { + get() { + const value = fromStream[property]; + const isFunction = typeof value === 'function'; + + return isFunction ? value.bind(fromStream) : value; + }, + set(value) { + fromStream[property] = value; + }, + enumerable: true, + configurable: false + }; + } + + Object.defineProperties(toStream, properties); + + fromStream.once('aborted', () => { + toStream.destroy(); + + toStream.emit('aborted'); + }); + + fromStream.once('close', () => { + if (fromStream.complete) { + if (toStream.readable) { + toStream.once('end', () => { + toStream.emit('close'); + }); + } else { + toStream.emit('close'); + } + } else { + toStream.emit('close'); + } + }); + + return toStream; +}; + + +/***/ }), + +/***/ 557: +/***/ (function(module) { + +"use strict"; + + +class CancelError extends Error { + constructor(reason) { + super(reason || 'Promise was canceled'); + this.name = 'CancelError'; + } + + get isCanceled() { + return true; + } +} + +class PCancelable { + static fn(userFn) { + return (...arguments_) => { + return new PCancelable((resolve, reject, onCancel) => { + arguments_.push(onCancel); + // eslint-disable-next-line promise/prefer-await-to-then + userFn(...arguments_).then(resolve, reject); + }); + }; + } + + constructor(executor) { + this._cancelHandlers = []; + this._isPending = true; + this._isCanceled = false; + this._rejectOnCancel = true; + + this._promise = new Promise((resolve, reject) => { + this._reject = reject; + + const onResolve = value => { + this._isPending = false; + resolve(value); + }; + + const onReject = error => { + this._isPending = false; + reject(error); + }; + + const onCancel = handler => { + if (!this._isPending) { + throw new Error('The `onCancel` handler was attached after the promise settled.'); + } + + this._cancelHandlers.push(handler); + }; + + Object.defineProperties(onCancel, { + shouldReject: { + get: () => this._rejectOnCancel, + set: boolean => { + this._rejectOnCancel = boolean; + } + } + }); + + return executor(onResolve, onReject, onCancel); + }); + } + + then(onFulfilled, onRejected) { + // eslint-disable-next-line promise/prefer-await-to-then + return this._promise.then(onFulfilled, onRejected); + } + + catch(onRejected) { + return this._promise.catch(onRejected); + } + + finally(onFinally) { + return this._promise.finally(onFinally); + } + + cancel(reason) { + if (!this._isPending || this._isCanceled) { + return; + } + + if (this._cancelHandlers.length > 0) { + try { + for (const handler of this._cancelHandlers) { + handler(); + } + } catch (error) { + this._reject(error); + } + } + + this._isCanceled = true; + if (this._rejectOnCancel) { + this._reject(new CancelError(reason)); + } + } + + get isCanceled() { + return this._isCanceled; + } +} + +Object.setPrototypeOf(PCancelable.prototype, Promise.prototype); + +module.exports = PCancelable; +module.exports.CancelError = CancelError; + + +/***/ }), + +/***/ 565: +/***/ (function(module) { + +module.exports = require("http2"); + +/***/ }), + +/***/ 570: +/***/ (function(module, __unusedexports, __webpack_require__) { + +"use strict"; + +const { + V4MAPPED, + ADDRCONFIG, + ALL, + promises: { + Resolver: AsyncResolver + }, + lookup: dnsLookup +} = __webpack_require__(881); +const {promisify} = __webpack_require__(669); +const os = __webpack_require__(87); + +const kCacheableLookupCreateConnection = Symbol('cacheableLookupCreateConnection'); +const kCacheableLookupInstance = Symbol('cacheableLookupInstance'); +const kExpires = Symbol('expires'); + +const supportsALL = typeof ALL === 'number'; + +const verifyAgent = agent => { + if (!(agent && typeof agent.createConnection === 'function')) { + throw new Error('Expected an Agent instance as the first argument'); + } +}; + +const map4to6 = entries => { + for (const entry of entries) { + if (entry.family === 6) { + continue; + } + + entry.address = `::ffff:${entry.address}`; + entry.family = 6; + } +}; + +const getIfaceInfo = () => { + let has4 = false; + let has6 = false; + + for (const device of Object.values(os.networkInterfaces())) { + for (const iface of device) { + if (iface.internal) { + continue; + } + + if (iface.family === 'IPv6') { + has6 = true; + } else { + has4 = true; + } + + if (has4 && has6) { + return {has4, has6}; + } + } + } + + return {has4, has6}; +}; + +const isIterable = map => { + return Symbol.iterator in map; +}; + +const ttl = {ttl: true}; +const all = {all: true}; + +class CacheableLookup { + constructor({ + cache = new Map(), + maxTtl = Infinity, + fallbackDuration = 3600, + errorTtl = 0.15, + resolver = new AsyncResolver(), + lookup = dnsLookup + } = {}) { + this.maxTtl = maxTtl; + this.errorTtl = errorTtl; + + this._cache = cache; + this._resolver = resolver; + this._dnsLookup = promisify(lookup); + + if (this._resolver instanceof AsyncResolver) { + this._resolve4 = this._resolver.resolve4.bind(this._resolver); + this._resolve6 = this._resolver.resolve6.bind(this._resolver); + } else { + this._resolve4 = promisify(this._resolver.resolve4.bind(this._resolver)); + this._resolve6 = promisify(this._resolver.resolve6.bind(this._resolver)); + } + + this._iface = getIfaceInfo(); + + this._pending = {}; + this._nextRemovalTime = false; + this._hostnamesToFallback = new Set(); + + if (fallbackDuration < 1) { + this._fallback = false; + } else { + this._fallback = true; + + const interval = setInterval(() => { + this._hostnamesToFallback.clear(); + }, fallbackDuration * 1000); + + /* istanbul ignore next: There is no `interval.unref()` when running inside an Electron renderer */ + if (interval.unref) { + interval.unref(); + } + } + + this.lookup = this.lookup.bind(this); + this.lookupAsync = this.lookupAsync.bind(this); + } + + set servers(servers) { + this.clear(); + + this._resolver.setServers(servers); + } + + get servers() { + return this._resolver.getServers(); + } + + lookup(hostname, options, callback) { + if (typeof options === 'function') { + callback = options; + options = {}; + } else if (typeof options === 'number') { + options = { + family: options + }; + } + + if (!callback) { + throw new Error('Callback must be a function.'); + } + + // eslint-disable-next-line promise/prefer-await-to-then + this.lookupAsync(hostname, options).then(result => { + if (options.all) { + callback(null, result); + } else { + callback(null, result.address, result.family, result.expires, result.ttl); + } + }, callback); + } + + async lookupAsync(hostname, options = {}) { + if (typeof options === 'number') { + options = { + family: options + }; + } + + let cached = await this.query(hostname); + + if (options.family === 6) { + const filtered = cached.filter(entry => entry.family === 6); + + if (options.hints & V4MAPPED) { + if ((supportsALL && options.hints & ALL) || filtered.length === 0) { + map4to6(cached); + } else { + cached = filtered; + } + } else { + cached = filtered; + } + } else if (options.family === 4) { + cached = cached.filter(entry => entry.family === 4); + } + + if (options.hints & ADDRCONFIG) { + const {_iface} = this; + cached = cached.filter(entry => entry.family === 6 ? _iface.has6 : _iface.has4); + } + + if (cached.length === 0) { + const error = new Error(`cacheableLookup ENOTFOUND ${hostname}`); + error.code = 'ENOTFOUND'; + error.hostname = hostname; + + throw error; + } + + if (options.all) { + return cached; + } + + return cached[0]; + } + + async query(hostname) { + let cached = await this._cache.get(hostname); + + if (!cached) { + const pending = this._pending[hostname]; + + if (pending) { + cached = await pending; + } else { + const newPromise = this.queryAndCache(hostname); + this._pending[hostname] = newPromise; + + cached = await newPromise; + } + } + + cached = cached.map(entry => { + return {...entry}; + }); + + return cached; + } + + async _resolve(hostname) { + const wrap = async promise => { + try { + return await promise; + } catch (error) { + if (error.code === 'ENODATA' || error.code === 'ENOTFOUND') { + return []; + } + + throw error; + } + }; + + // ANY is unsafe as it doesn't trigger new queries in the underlying server. + const [A, AAAA] = await Promise.all([ + this._resolve4(hostname, ttl), + this._resolve6(hostname, ttl) + ].map(promise => wrap(promise))); + + let aTtl = 0; + let aaaaTtl = 0; + let cacheTtl = 0; + + const now = Date.now(); + + for (const entry of A) { + entry.family = 4; + entry.expires = now + (entry.ttl * 1000); + + aTtl = Math.max(aTtl, entry.ttl); + } + + for (const entry of AAAA) { + entry.family = 6; + entry.expires = now + (entry.ttl * 1000); + + aaaaTtl = Math.max(aaaaTtl, entry.ttl); + } + + if (A.length > 0) { + if (AAAA.length > 0) { + cacheTtl = Math.min(aTtl, aaaaTtl); + } else { + cacheTtl = aTtl; + } + } else { + cacheTtl = aaaaTtl; + } + + return { + entries: [ + ...A, + ...AAAA + ], + cacheTtl + }; + } + + async _lookup(hostname) { + try { + const entries = await this._dnsLookup(hostname, { + all: true + }); + + return { + entries, + cacheTtl: 0 + }; + } catch (_) { + return { + entries: [], + cacheTtl: 0 + }; + } + } + + async _set(hostname, data, cacheTtl) { + if (this.maxTtl > 0 && cacheTtl > 0) { + cacheTtl = Math.min(cacheTtl, this.maxTtl) * 1000; + data[kExpires] = Date.now() + cacheTtl; + + try { + await this._cache.set(hostname, data, cacheTtl); + } catch (error) { + this.lookupAsync = async () => { + const cacheError = new Error('Cache Error. Please recreate the CacheableLookup instance.'); + cacheError.cause = error; + + throw cacheError; + }; + } + + if (isIterable(this._cache)) { + this._tick(cacheTtl); + } + } + } + + async queryAndCache(hostname) { + if (this._hostnamesToFallback.has(hostname)) { + return this._dnsLookup(hostname, all); + } + + try { + let query = await this._resolve(hostname); + + if (query.entries.length === 0 && this._fallback) { + query = await this._lookup(hostname); + + if (query.entries.length !== 0) { + // Use `dns.lookup(...)` for that particular hostname + this._hostnamesToFallback.add(hostname); + } + } + + const cacheTtl = query.entries.length === 0 ? this.errorTtl : query.cacheTtl; + await this._set(hostname, query.entries, cacheTtl); + + delete this._pending[hostname]; + + return query.entries; + } catch (error) { + delete this._pending[hostname]; + + throw error; + } + } + + _tick(ms) { + const nextRemovalTime = this._nextRemovalTime; + + if (!nextRemovalTime || ms < nextRemovalTime) { + clearTimeout(this._removalTimeout); + + this._nextRemovalTime = ms; + + this._removalTimeout = setTimeout(() => { + this._nextRemovalTime = false; + + let nextExpiry = Infinity; + + const now = Date.now(); + + for (const [hostname, entries] of this._cache) { + const expires = entries[kExpires]; + + if (now >= expires) { + this._cache.delete(hostname); + } else if (expires < nextExpiry) { + nextExpiry = expires; + } + } + + if (nextExpiry !== Infinity) { + this._tick(nextExpiry - now); + } + }, ms); + + /* istanbul ignore next: There is no `timeout.unref()` when running inside an Electron renderer */ + if (this._removalTimeout.unref) { + this._removalTimeout.unref(); + } + } + } + + install(agent) { + verifyAgent(agent); + + if (kCacheableLookupCreateConnection in agent) { + throw new Error('CacheableLookup has been already installed'); + } + + agent[kCacheableLookupCreateConnection] = agent.createConnection; + agent[kCacheableLookupInstance] = this; + + agent.createConnection = (options, callback) => { + if (!('lookup' in options)) { + options.lookup = this.lookup; + } + + return agent[kCacheableLookupCreateConnection](options, callback); + }; + } + + uninstall(agent) { + verifyAgent(agent); + + if (agent[kCacheableLookupCreateConnection]) { + if (agent[kCacheableLookupInstance] !== this) { + throw new Error('The agent is not owned by this CacheableLookup instance'); + } + + agent.createConnection = agent[kCacheableLookupCreateConnection]; + + delete agent[kCacheableLookupCreateConnection]; + delete agent[kCacheableLookupInstance]; + } + } + + updateInterfaceInfo() { + const {_iface} = this; + + this._iface = getIfaceInfo(); + + if ((_iface.has4 && !this._iface.has4) || (_iface.has6 && !this._iface.has6)) { + this._cache.clear(); + } + } + + clear(hostname) { + if (hostname) { + this._cache.delete(hostname); + return; + } + + this._cache.clear(); + } +} + +module.exports = CacheableLookup; +module.exports.default = CacheableLookup; + + +/***/ }), + +/***/ 577: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PromisableRequest = void 0; +const events_1 = __webpack_require__(614); +const PCancelable = __webpack_require__(557); +const calculate_retry_delay_1 = __webpack_require__(927); +const types_1 = __webpack_require__(36); +const core_1 = __webpack_require__(468); +exports.PromisableRequest = core_1.default; +const proxy_events_1 = __webpack_require__(628); +const get_buffer_1 = __webpack_require__(452); +const proxiedRequestEvents = [ + 'request', + 'response', + 'redirect', + 'uploadProgress', + 'downloadProgress' +]; +function asPromise(options) { + let retryCount = 0; + let globalRequest; + let globalResponse; + const emitter = new events_1.EventEmitter(); + const promise = new PCancelable((resolve, _reject, onCancel) => { + const makeRequest = () => { + // Support retries + // `options.throwHttpErrors` needs to be always true, + // so the HTTP errors are caught and the request is retried. + // The error is **eventually** thrown if the user value is true. + const { throwHttpErrors } = options; + if (!throwHttpErrors) { + options.throwHttpErrors = true; + } + // Note from @szmarczak: I think we should use `request.options` instead of the local options + const request = new core_1.default(options.url, options); + request._noPipe = true; + onCancel(() => request.destroy()); + const reject = (error) => { + void (async () => { + try { + for (const hook of options.hooks.beforeError) { + // eslint-disable-next-line no-await-in-loop + error = await hook(error); + } + } + catch (error_) { + _reject(new types_1.RequestError(error_.message, error_, request)); + return; + } + _reject(error); + })(); + }; + globalRequest = request; + const onResponse = async (response) => { + var _a; + response.retryCount = retryCount; + if (response.request.aborted) { + // Canceled while downloading - will throw a `CancelError` or `TimeoutError` error + return; + } + const isOk = () => { + const { statusCode } = response; + const limitStatusCode = options.followRedirect ? 299 : 399; + return (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304; + }; + // Download body + let rawBody; + try { + rawBody = await get_buffer_1.default(request); + response.rawBody = rawBody; + } + catch (_b) { + // The same error is caught below. + // See request.once('error') + return; + } + // Parse body + const contentEncoding = ((_a = response.headers['content-encoding']) !== null && _a !== void 0 ? _a : '').toLowerCase(); + const isCompressed = ['gzip', 'deflate', 'br'].includes(contentEncoding); + if (isCompressed && !options.decompress) { + response.body = rawBody; + } + else { + try { + response.body = core_1.parseBody(response, options.responseType, options.parseJson, options.encoding); + } + catch (error) { + // Fallback to `utf8` + response.body = rawBody.toString(); + if (isOk()) { + // TODO: Call `request._beforeError`, see https://github.com/nodejs/node/issues/32995 + reject(error); + return; + } + } + } + try { + for (const [index, hook] of options.hooks.afterResponse.entries()) { + // @ts-expect-error TS doesn't notice that CancelableRequest is a Promise + // eslint-disable-next-line no-await-in-loop + response = await hook(response, async (updatedOptions) => { + const typedOptions = core_1.default.normalizeArguments(undefined, { + ...updatedOptions, + retry: { + calculateDelay: () => 0 + }, + throwHttpErrors: false, + resolveBodyOnly: false + }, options); + // Remove any further hooks for that request, because we'll call them anyway. + // The loop continues. We don't want duplicates (asPromise recursion). + typedOptions.hooks.afterResponse = typedOptions.hooks.afterResponse.slice(0, index); + for (const hook of typedOptions.hooks.beforeRetry) { + // eslint-disable-next-line no-await-in-loop + await hook(typedOptions); + } + const promise = asPromise(typedOptions); + onCancel(() => { + promise.catch(() => { }); + promise.cancel(); + }); + return promise; + }); + } + } + catch (error) { + // TODO: Call `request._beforeError`, see https://github.com/nodejs/node/issues/32995 + reject(new types_1.RequestError(error.message, error, request)); + return; + } + if (throwHttpErrors && !isOk()) { + reject(new types_1.HTTPError(response)); + return; + } + globalResponse = response; + resolve(options.resolveBodyOnly ? response.body : response); + }; + const onError = async (error) => { + if (promise.isCanceled) { + return; + } + if (!request.options) { + reject(error); + return; + } + request.off('response', onResponse); + let gotUnexpectedError = false; + const onUnexpectedError = (error) => { + gotUnexpectedError = true; + reject(error); + }; + // If this is an HTTP error, then it can throw again with `ECONNRESET` or `Parse Error` + request.once('error', onUnexpectedError); + let backoff; + retryCount++; + try { + backoff = await options.retry.calculateDelay({ + attemptCount: retryCount, + retryOptions: options.retry, + error, + computedValue: calculate_retry_delay_1.default({ + attemptCount: retryCount, + retryOptions: options.retry, + error, + computedValue: 0 + }) + }); + } + catch (error_) { + // Don't emit the `response` event + request.destroy(); + reject(new types_1.RequestError(error_.message, error, request)); + return; + } + // Another error was thrown already + if (gotUnexpectedError) { + return; + } + request.off('error', onUnexpectedError); + if (backoff) { + // Don't emit the `response` event + request.destroy(); + const retry = async () => { + options.throwHttpErrors = throwHttpErrors; + try { + for (const hook of options.hooks.beforeRetry) { + // eslint-disable-next-line no-await-in-loop + await hook(options, error, retryCount); + } + } + catch (error_) { + // Don't emit the `response` event + request.destroy(); + reject(new types_1.RequestError(error_.message, error, request)); + return; + } + makeRequest(); + }; + setTimeout(retry, backoff); + return; + } + // The retry has not been made + retryCount--; + if (error instanceof types_1.HTTPError) { + // The error will be handled by the `response` event + void onResponse(request._response); + // Reattach the error handler, because there may be a timeout later. + request.once('error', onError); + return; + } + // Don't emit the `response` event + request.destroy(); + reject(error); + }; + request.once('response', onResponse); + request.once('error', onError); + proxy_events_1.default(request, emitter, proxiedRequestEvents); + }; + makeRequest(); + }); + promise.on = (event, fn) => { + emitter.on(event, fn); + return promise; + }; + const shortcut = (responseType) => { + const newPromise = (async () => { + // Wait until downloading has ended + await promise; + return core_1.parseBody(globalResponse, responseType, options.parseJson, options.encoding); + })(); + Object.defineProperties(newPromise, Object.getOwnPropertyDescriptors(promise)); + return newPromise; + }; + promise.json = () => { + if (!globalRequest.writableFinished && options.headers.accept === undefined) { + options.headers.accept = 'application/json'; + } + return shortcut('json'); + }; + promise.buffer = () => shortcut('buffer'); + promise.text = () => shortcut('text'); + return promise; +} +exports.default = asPromise; +__exportStar(__webpack_require__(36), exports); + + +/***/ }), + +/***/ 605: +/***/ (function(module) { + +module.exports = require("http"); + +/***/ }), + +/***/ 614: +/***/ (function(module) { + +module.exports = require("events"); + +/***/ }), + +/***/ 622: +/***/ (function(module) { + +module.exports = require("path"); + +/***/ }), + +/***/ 628: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function default_1(from, to, events) { + const fns = {}; + for (const event of events) { + fns[event] = (...args) => { + to.emit(event, ...args); + }; + from.on(event, fns[event]); + } + return () => { + for (const event of events) { + from.off(event, fns[event]); + } + }; +} +exports.default = default_1; + + +/***/ }), + +/***/ 631: +/***/ (function(module) { + +module.exports = require("net"); + +/***/ }), + +/***/ 669: +/***/ (function(module) { + +module.exports = require("util"); + +/***/ }), + +/***/ 676: +/***/ (function(module, __unusedexports, __webpack_require__) { + +const auth = __webpack_require__(151); +const secrets = __webpack_require__(461); + +module.exports = { + auth, + secrets +}; + +/***/ }), + +/***/ 699: +/***/ (function(module) { + +"use strict"; + +/* istanbul ignore file: https://github.com/nodejs/node/blob/master/lib/internal/errors.js */ + +const makeError = (Base, key, getMessage) => { + module.exports[key] = class NodeError extends Base { + constructor(...args) { + super(typeof getMessage === 'string' ? getMessage : getMessage(args)); + this.name = `${super.name} [${key}]`; + this.code = key; + } + }; +}; + +makeError(TypeError, 'ERR_INVALID_ARG_TYPE', args => { + const type = args[0].includes('.') ? 'property' : 'argument'; + + let valid = args[1]; + const isManyTypes = Array.isArray(valid); + + if (isManyTypes) { + valid = `${valid.slice(0, -1).join(', ')} or ${valid.slice(-1)}`; + } + + return `The "${args[0]}" ${type} must be ${isManyTypes ? 'one of' : 'of'} type ${valid}. Received ${typeof args[2]}`; +}); + +makeError(TypeError, 'ERR_INVALID_PROTOCOL', args => { + return `Protocol "${args[0]}" not supported. Expected "${args[1]}"`; +}); + +makeError(Error, 'ERR_HTTP_HEADERS_SENT', args => { + return `Cannot ${args[0]} headers after they are sent to the client`; +}); + +makeError(TypeError, 'ERR_INVALID_HTTP_TOKEN', args => { + return `${args[0]} must be a valid HTTP token [${args[1]}]`; +}); + +makeError(TypeError, 'ERR_HTTP_INVALID_HEADER_VALUE', args => { + return `Invalid value "${args[0]} for header "${args[1]}"`; +}); + +makeError(TypeError, 'ERR_INVALID_CHAR', args => { + return `Invalid character in ${args[0]} [${args[1]}]`; +}); + + +/***/ }), + +/***/ 723: +/***/ (function(module) { + +"use strict"; + + +module.exports = header => { + switch (header) { + case ':method': + case ':scheme': + case ':authority': + case ':path': + return true; + default: + return false; + } +}; + + +/***/ }), + +/***/ 738: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.dnsLookupIpVersionToFamily = exports.isDnsLookupIpVersion = void 0; +const conversionTable = { + auto: 0, + ipv4: 4, + ipv6: 6 +}; +exports.isDnsLookupIpVersion = (value) => { + return value in conversionTable; +}; +exports.dnsLookupIpVersionToFamily = (dnsLookupIpVersion) => { + if (exports.isDnsLookupIpVersion(dnsLookupIpVersion)) { + return conversionTable[dnsLookupIpVersion]; + } + throw new Error('Invalid DNS lookup IP version'); +}; + + +/***/ }), + +/***/ 747: +/***/ (function(module) { + +module.exports = require("fs"); + +/***/ }), + +/***/ 750: +/***/ (function(module, __unusedexports, __webpack_require__) { + +"use strict"; + +const {Readable} = __webpack_require__(413); + +class IncomingMessage extends Readable { + constructor(socket, highWaterMark) { + super({ + highWaterMark, + autoDestroy: false + }); + + this.statusCode = null; + this.statusMessage = ''; + this.httpVersion = '2.0'; + this.httpVersionMajor = 2; + this.httpVersionMinor = 0; + this.headers = {}; + this.trailers = {}; + this.req = null; + + this.aborted = false; + this.complete = false; + this.upgrade = null; + + this.rawHeaders = []; + this.rawTrailers = []; + + this.socket = socket; + this.connection = socket; + + this._dumped = false; + } + + _destroy(error) { + this.req._request.destroy(error); + } + + setTimeout(ms, callback) { + this.req.setTimeout(ms, callback); + return this; + } + + _dump() { + if (!this._dumped) { + this._dumped = true; + + this.removeAllListeners('data'); + this.resume(); + } + } + + _read() { + if (this.req) { + this.req._request.resume(); + } + } +} + +module.exports = IncomingMessage; + + +/***/ }), + +/***/ 751: +/***/ (function(module, __unusedexports, __webpack_require__) { + +"use strict"; + +const net = __webpack_require__(631); +/* istanbul ignore file: https://github.com/nodejs/node/blob/v13.0.1/lib/_http_agent.js */ + +module.exports = options => { + let servername = options.host; + const hostHeader = options.headers && options.headers.host; + + if (hostHeader) { + if (hostHeader.startsWith('[')) { + const index = hostHeader.indexOf(']'); + if (index === -1) { + servername = hostHeader; + } else { + servername = hostHeader.slice(1, -1); + } + } else { + servername = hostHeader.split(':', 1)[0]; + } + } + + if (net.isIP(servername)) { + return ''; + } + + return servername; +}; + + +/***/ }), + +/***/ 761: +/***/ (function(module) { + +module.exports = require("zlib"); + +/***/ }), + +/***/ 784: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +// When attaching listeners, it's very easy to forget about them. +// Especially if you do error handling and set timeouts. +// So instead of checking if it's proper to throw an error on every timeout ever, +// use this simple tool which will remove all listeners you have attached. +exports.default = () => { + const handlers = []; + return { + once(origin, event, fn) { + origin.once(event, fn); + handlers.push({ origin, event, fn }); + }, + unhandleAll() { + for (const handler of handlers) { + const { origin, event, fn } = handler; + origin.removeListener(event, fn); + } + handlers.length = 0; + } + }; +}; + + +/***/ }), + +/***/ 786: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = __webpack_require__(747); +const util_1 = __webpack_require__(669); +const is_1 = __webpack_require__(534); +const is_form_data_1 = __webpack_require__(460); +const statAsync = util_1.promisify(fs_1.stat); +exports.default = async (body, headers) => { + if (headers && 'content-length' in headers) { + return Number(headers['content-length']); + } + if (!body) { + return 0; + } + if (is_1.default.string(body)) { + return Buffer.byteLength(body); + } + if (is_1.default.buffer(body)) { + return body.length; + } + if (is_form_data_1.default(body)) { + return util_1.promisify(body.getLength.bind(body))(); + } + if (body instanceof fs_1.ReadStream) { + const { size } = await statAsync(body.path); + return size; + } + return undefined; +}; + + +/***/ }), + +/***/ 790: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const tls_1 = __webpack_require__(16); +const deferToConnect = (socket, fn) => { + let listeners; + if (typeof fn === 'function') { + const connect = fn; + listeners = { connect }; + } + else { + listeners = fn; + } + const hasConnectListener = typeof listeners.connect === 'function'; + const hasSecureConnectListener = typeof listeners.secureConnect === 'function'; + const hasCloseListener = typeof listeners.close === 'function'; + const onConnect = () => { + if (hasConnectListener) { + listeners.connect(); + } + if (socket instanceof tls_1.TLSSocket && hasSecureConnectListener) { + if (socket.authorized) { + listeners.secureConnect(); + } + else if (!socket.authorizationError) { + socket.once('secureConnect', listeners.secureConnect); + } + } + if (hasCloseListener) { + socket.once('close', listeners.close); + } + }; + if (socket.writable && !socket.connecting) { + onConnect(); + } + else if (socket.connecting) { + socket.once('connect', onConnect); + } + else if (socket.destroyed && hasCloseListener) { + listeners.close(socket._hadError); + } +}; +exports.default = deferToConnect; +// For CommonJS default export support +module.exports = deferToConnect; +module.exports.default = deferToConnect; + + +/***/ }), + +/***/ 811: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TimeoutError = void 0; +const net = __webpack_require__(631); +const unhandle_1 = __webpack_require__(784); +const reentry = Symbol('reentry'); +const noop = () => { }; +class TimeoutError extends Error { + constructor(threshold, event) { + super(`Timeout awaiting '${event}' for ${threshold}ms`); + this.event = event; + this.name = 'TimeoutError'; + this.code = 'ETIMEDOUT'; + } +} +exports.TimeoutError = TimeoutError; +exports.default = (request, delays, options) => { + if (reentry in request) { + return noop; + } + request[reentry] = true; + const cancelers = []; + const { once, unhandleAll } = unhandle_1.default(); + const addTimeout = (delay, callback, event) => { + var _a; + const timeout = setTimeout(callback, delay, delay, event); + (_a = timeout.unref) === null || _a === void 0 ? void 0 : _a.call(timeout); + const cancel = () => { + clearTimeout(timeout); + }; + cancelers.push(cancel); + return cancel; + }; + const { host, hostname } = options; + const timeoutHandler = (delay, event) => { + request.destroy(new TimeoutError(delay, event)); + }; + const cancelTimeouts = () => { + for (const cancel of cancelers) { + cancel(); + } + unhandleAll(); + }; + request.once('error', error => { + cancelTimeouts(); + // Save original behavior + /* istanbul ignore next */ + if (request.listenerCount('error') === 0) { + throw error; + } + }); + request.once('close', cancelTimeouts); + once(request, 'response', (response) => { + once(response, 'end', cancelTimeouts); + }); + if (typeof delays.request !== 'undefined') { + addTimeout(delays.request, timeoutHandler, 'request'); + } + if (typeof delays.socket !== 'undefined') { + const socketTimeoutHandler = () => { + timeoutHandler(delays.socket, 'socket'); + }; + request.setTimeout(delays.socket, socketTimeoutHandler); + // `request.setTimeout(0)` causes a memory leak. + // We can just remove the listener and forget about the timer - it's unreffed. + // See https://github.com/sindresorhus/got/issues/690 + cancelers.push(() => { + request.removeListener('timeout', socketTimeoutHandler); + }); + } + once(request, 'socket', (socket) => { + var _a; + const { socketPath } = request; + /* istanbul ignore next: hard to test */ + if (socket.connecting) { + const hasPath = Boolean(socketPath !== null && socketPath !== void 0 ? socketPath : net.isIP((_a = hostname !== null && hostname !== void 0 ? hostname : host) !== null && _a !== void 0 ? _a : '') !== 0); + if (typeof delays.lookup !== 'undefined' && !hasPath && typeof socket.address().address === 'undefined') { + const cancelTimeout = addTimeout(delays.lookup, timeoutHandler, 'lookup'); + once(socket, 'lookup', cancelTimeout); + } + if (typeof delays.connect !== 'undefined') { + const timeConnect = () => addTimeout(delays.connect, timeoutHandler, 'connect'); + if (hasPath) { + once(socket, 'connect', timeConnect()); + } + else { + once(socket, 'lookup', (error) => { + if (error === null) { + once(socket, 'connect', timeConnect()); + } + }); + } + } + if (typeof delays.secureConnect !== 'undefined' && options.protocol === 'https:') { + once(socket, 'connect', () => { + const cancelTimeout = addTimeout(delays.secureConnect, timeoutHandler, 'secureConnect'); + once(socket, 'secureConnect', cancelTimeout); + }); + } + } + if (typeof delays.send !== 'undefined') { + const timeRequest = () => addTimeout(delays.send, timeoutHandler, 'send'); + /* istanbul ignore next: hard to test */ + if (socket.connecting) { + once(socket, 'connect', () => { + once(request, 'upload-complete', timeRequest()); + }); + } + else { + once(request, 'upload-complete', timeRequest()); + } + } + }); + if (typeof delays.response !== 'undefined') { + once(request, 'upload-complete', () => { + const cancelTimeout = addTimeout(delays.response, timeoutHandler, 'response'); + once(request, 'response', cancelTimeout); + }); + } + return cancelTimeouts; +}; /***/ }), -/***/ 557: +/***/ 835: /***/ (function(module) { -"use strict"; - - -class CancelError extends Error { - constructor(reason) { - super(reason || 'Promise was canceled'); - this.name = 'CancelError'; - } +module.exports = require("url"); - get isCanceled() { - return true; - } -} +/***/ }), -class PCancelable { - static fn(userFn) { - return (...arguments_) => { - return new PCancelable((resolve, reject, onCancel) => { - arguments_.push(onCancel); - // eslint-disable-next-line promise/prefer-await-to-then - userFn(...arguments_).then(resolve, reject); - }); - }; - } +/***/ 839: +/***/ (function(__unusedmodule, exports) { - constructor(executor) { - this._cancelHandlers = []; - this._isPending = true; - this._isCanceled = false; - this._rejectOnCancel = true; +"use strict"; - this._promise = new Promise((resolve, reject) => { - this._reject = reject; +Object.defineProperty(exports, "__esModule", { value: true }); - const onResolve = value => { - this._isPending = false; - resolve(value); - }; - const onReject = error => { - this._isPending = false; - reject(error); - }; +/***/ }), - const onCancel = handler => { - if (!this._isPending) { - throw new Error('The `onCancel` handler was attached after the promise settled.'); - } +/***/ 861: +/***/ (function(module, __unusedexports, __webpack_require__) { - this._cancelHandlers.push(handler); - }; +"use strict"; - Object.defineProperties(onCancel, { - shouldReject: { - get: () => this._rejectOnCancel, - set: boolean => { - this._rejectOnCancel = boolean; - } - } - }); +const {Transform, PassThrough} = __webpack_require__(413); +const zlib = __webpack_require__(761); +const mimicResponse = __webpack_require__(537); - return executor(onResolve, onReject, onCancel); - }); - } +module.exports = response => { + const contentEncoding = (response.headers['content-encoding'] || '').toLowerCase(); - then(onFulfilled, onRejected) { - // eslint-disable-next-line promise/prefer-await-to-then - return this._promise.then(onFulfilled, onRejected); + if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) { + return response; } - catch(onRejected) { - return this._promise.catch(onRejected); + // TODO: Remove this when targeting Node.js 12. + const isBrotli = contentEncoding === 'br'; + if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') { + response.destroy(new Error('Brotli is not supported on Node.js < 12')); + return response; } - finally(onFinally) { - return this._promise.finally(onFinally); - } + let isEmpty = true; - cancel(reason) { - if (!this._isPending || this._isCanceled) { - return; - } + const checker = new Transform({ + transform(data, _encoding, callback) { + isEmpty = false; - if (this._cancelHandlers.length > 0) { - try { - for (const handler of this._cancelHandlers) { - handler(); - } - } catch (error) { - this._reject(error); - } - } + callback(null, data); + }, - this._isCanceled = true; - if (this._rejectOnCancel) { - this._reject(new CancelError(reason)); + flush(callback) { + callback(); } - } - - get isCanceled() { - return this._isCanceled; - } -} - -Object.setPrototypeOf(PCancelable.prototype, Promise.prototype); + }); -module.exports = PCancelable; -module.exports.CancelError = CancelError; + const finalStream = new PassThrough({ + autoDestroy: false, + destroy(error, callback) { + response.destroy(); + callback(error); + } + }); -/***/ }), + const decompressStream = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip(); -/***/ 605: -/***/ (function(module) { + decompressStream.once('error', error => { + if (isEmpty && !response.readable) { + finalStream.end(); + return; + } -module.exports = require("http"); + finalStream.destroy(error); + }); -/***/ }), + mimicResponse(response, finalStream); + response.pipe(checker).pipe(decompressStream).pipe(finalStream); -/***/ 614: -/***/ (function(module) { + return finalStream; +}; -module.exports = require("events"); /***/ }), -/***/ 616: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const EventEmitter = __webpack_require__(614); -const getStream = __webpack_require__(705); -const PCancelable = __webpack_require__(557); -const is_1 = __webpack_require__(534); -const errors_1 = __webpack_require__(378); -const normalize_arguments_1 = __webpack_require__(110); -const request_as_event_emitter_1 = __webpack_require__(872); -const parseBody = (body, responseType, encoding) => { - if (responseType === 'json') { - return body.length === 0 ? '' : JSON.parse(body.toString()); - } - if (responseType === 'buffer') { - return Buffer.from(body); - } - if (responseType === 'text') { - return body.toString(encoding); - } - throw new TypeError(`Unknown body type '${responseType}'`); -}; -function createRejection(error) { - const promise = Promise.reject(error); - const returnPromise = () => promise; - promise.json = returnPromise; - promise.text = returnPromise; - promise.buffer = returnPromise; - promise.on = returnPromise; - return promise; -} -exports.createRejection = createRejection; -function asPromise(options) { - const proxy = new EventEmitter(); - let body; - const promise = new PCancelable((resolve, reject, onCancel) => { - const emitter = request_as_event_emitter_1.default(options); - onCancel(emitter.abort); - const emitError = async (error) => { - try { - for (const hook of options.hooks.beforeError) { - // eslint-disable-next-line no-await-in-loop - error = await hook(error); - } - reject(error); - } - catch (error_) { - reject(error_); - } - }; - emitter.on('response', async (response) => { - var _a; - proxy.emit('response', response); - // Download body - try { - body = await getStream.buffer(response, { encoding: 'binary' }); - } - catch (error) { - emitError(new errors_1.ReadError(error, options)); - return; - } - if ((_a = response.req) === null || _a === void 0 ? void 0 : _a.aborted) { - // Canceled while downloading - will throw a `CancelError` or `TimeoutError` error - return; - } - const isOk = () => { - const { statusCode } = response; - const limitStatusCode = options.followRedirect ? 299 : 399; - return (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304; - }; - // Parse body - try { - response.body = parseBody(body, options.responseType, options.encoding); - } - catch (error) { - // Fall back to `utf8` - response.body = body.toString(); - if (isOk()) { - const parseError = new errors_1.ParseError(error, response, options); - emitError(parseError); - return; - } - } - try { - for (const [index, hook] of options.hooks.afterResponse.entries()) { - // @ts-ignore TS doesn't notice that CancelableRequest is a Promise - // eslint-disable-next-line no-await-in-loop - response = await hook(response, async (updatedOptions) => { - const typedOptions = normalize_arguments_1.normalizeArguments(normalize_arguments_1.mergeOptions(options, { - ...updatedOptions, - retry: { - calculateDelay: () => 0 - }, - throwHttpErrors: false, - resolveBodyOnly: false - })); - // Remove any further hooks for that request, because we'll call them anyway. - // The loop continues. We don't want duplicates (asPromise recursion). - typedOptions.hooks.afterResponse = options.hooks.afterResponse.slice(0, index); - for (const hook of options.hooks.beforeRetry) { - // eslint-disable-next-line no-await-in-loop - await hook(typedOptions); - } - const promise = asPromise(typedOptions); - onCancel(() => { - promise.catch(() => { }); - promise.cancel(); - }); - return promise; - }); - } - } - catch (error) { - emitError(error); - return; - } - // Check for HTTP error codes - if (!isOk()) { - const error = new errors_1.HTTPError(response, options); - if (emitter.retry(error)) { - return; - } - if (options.throwHttpErrors) { - emitError(error); - return; - } - } - resolve(options.resolveBodyOnly ? response.body : response); - }); - emitter.once('error', reject); - request_as_event_emitter_1.proxyEvents(proxy, emitter); - }); - promise.on = (name, fn) => { - proxy.on(name, fn); - return promise; - }; - const shortcut = (responseType) => { - // eslint-disable-next-line promise/prefer-await-to-then - const newPromise = promise.then(() => parseBody(body, responseType, options.encoding)); - Object.defineProperties(newPromise, Object.getOwnPropertyDescriptors(promise)); - return newPromise; - }; - promise.json = () => { - if (is_1.default.undefined(body) && is_1.default.undefined(options.headers.accept)) { - options.headers.accept = 'application/json'; - } - return shortcut('json'); - }; - promise.buffer = () => shortcut('buffer'); - promise.text = () => shortcut('text'); - return promise; -} -exports.default = asPromise; +/***/ 881: +/***/ (function(module) { +module.exports = require("dns"); /***/ }), -/***/ 620: -/***/ (function(__unusedmodule, exports, __webpack_require__) { +/***/ 899: +/***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const zlib = __webpack_require__(761); -exports.default = typeof zlib.createBrotliDecompress === 'function'; +const EventEmitter = __webpack_require__(614); +const tls = __webpack_require__(16); +const http2 = __webpack_require__(565); +const QuickLRU = __webpack_require__(904); + +const kCurrentStreamsCount = Symbol('currentStreamsCount'); +const kRequest = Symbol('request'); +const kOriginSet = Symbol('cachedOriginSet'); +const kGracefullyClosing = Symbol('gracefullyClosing'); + +const nameKeys = [ + // `http2.connect()` options + 'maxDeflateDynamicTableSize', + 'maxSessionMemory', + 'maxHeaderListPairs', + 'maxOutstandingPings', + 'maxReservedRemoteStreams', + 'maxSendHeaderBlockLength', + 'paddingStrategy', + + // `tls.connect()` options + 'localAddress', + 'path', + 'rejectUnauthorized', + 'minDHSize', + + // `tls.createSecureContext()` options + 'ca', + 'cert', + 'clientCertEngine', + 'ciphers', + 'key', + 'pfx', + 'servername', + 'minVersion', + 'maxVersion', + 'secureProtocol', + 'crl', + 'honorCipherOrder', + 'ecdhCurve', + 'dhparam', + 'secureOptions', + 'sessionIdContext' +]; +const getSortedIndex = (array, value, compare) => { + let low = 0; + let high = array.length; -/***/ }), + while (low < high) { + const mid = (low + high) >>> 1; -/***/ 622: -/***/ (function(module) { + /* istanbul ignore next */ + if (compare(array[mid], value)) { + // This never gets called because we use descending sort. Better to have this anyway. + low = mid + 1; + } else { + high = mid; + } + } -module.exports = require("path"); + return low; +}; -/***/ }), +const compareSessions = (a, b) => { + return a.remoteSettings.maxConcurrentStreams > b.remoteSettings.maxConcurrentStreams; +}; -/***/ 631: -/***/ (function(module) { +// See https://tools.ietf.org/html/rfc8336 +const closeCoveredSessions = (where, session) => { + // Clients SHOULD NOT emit new requests on any connection whose Origin + // Set is a proper subset of another connection's Origin Set, and they + // SHOULD close it once all outstanding requests are satisfied. + for (const coveredSession of where) { + if ( + // The set is a proper subset when its length is less than the other set. + coveredSession[kOriginSet].length < session[kOriginSet].length && + + // And the other set includes all elements of the subset. + coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) && + + // Makes sure that the session can handle all requests from the covered session. + coveredSession[kCurrentStreamsCount] + session[kCurrentStreamsCount] <= session.remoteSettings.maxConcurrentStreams + ) { + // This allows pending requests to finish and prevents making new requests. + gracefullyClose(coveredSession); + } + } +}; -module.exports = require("net"); +// This is basically inverted `closeCoveredSessions(...)`. +const closeSessionIfCovered = (where, coveredSession) => { + for (const session of where) { + if ( + coveredSession[kOriginSet].length < session[kOriginSet].length && + coveredSession[kOriginSet].every(origin => session[kOriginSet].includes(origin)) && + coveredSession[kCurrentStreamsCount] + session[kCurrentStreamsCount] <= session.remoteSettings.maxConcurrentStreams + ) { + gracefullyClose(coveredSession); + } + } +}; -/***/ }), +const getSessions = ({agent, isFree}) => { + const result = {}; -/***/ 654: -/***/ (function(module, __unusedexports, __webpack_require__) { + // eslint-disable-next-line guard-for-in + for (const normalizedOptions in agent.sessions) { + const sessions = agent.sessions[normalizedOptions]; -"use strict"; + const filtered = sessions.filter(session => { + const result = session[Agent.kCurrentStreamsCount] < session.remoteSettings.maxConcurrentStreams; + + return isFree ? result : !result; + }); -const pFinally = __webpack_require__(697); + if (filtered.length !== 0) { + result[normalizedOptions] = filtered; + } + } -class TimeoutError extends Error { - constructor(message) { - super(message); - this.name = 'TimeoutError'; + return result; +}; + +const gracefullyClose = session => { + session[kGracefullyClosing] = true; + + if (session[kCurrentStreamsCount] === 0) { + session.close(); } -} +}; + +class Agent extends EventEmitter { + constructor({timeout = 60000, maxSessions = Infinity, maxFreeSessions = 10, maxCachedTlsSessions = 100} = {}) { + super(); + + // A session is considered busy when its current streams count + // is equal to or greater than the `maxConcurrentStreams` value. + + // A session is considered free when its current streams count + // is less than the `maxConcurrentStreams` value. + + // SESSIONS[NORMALIZED_OPTIONS] = []; + this.sessions = {}; + + // The queue for creating new sessions. It looks like this: + // QUEUE[NORMALIZED_OPTIONS][NORMALIZED_ORIGIN] = ENTRY_FUNCTION + // + // The entry function has `listeners`, `completed` and `destroyed` properties. + // `listeners` is an array of objects containing `resolve` and `reject` functions. + // `completed` is a boolean. It's set to true after ENTRY_FUNCTION is executed. + // `destroyed` is a boolean. If it's set to true, the session will be destroyed if hasn't connected yet. + this.queue = {}; -module.exports = (promise, ms, fallback) => new Promise((resolve, reject) => { - if (typeof ms !== 'number' || ms < 0) { - throw new TypeError('Expected `ms` to be a positive number'); + // Each session will use this timeout value. + this.timeout = timeout; + + // Max sessions in total + this.maxSessions = maxSessions; + + // Max free sessions in total + // TODO: decreasing `maxFreeSessions` should close some sessions + this.maxFreeSessions = maxFreeSessions; + + this._freeSessionsCount = 0; + this._sessionsCount = 0; + + // We don't support push streams by default. + this.settings = { + enablePush: false + }; + + // Reusing TLS sessions increases performance. + this.tlsSessionCache = new QuickLRU({maxSize: maxCachedTlsSessions}); } - const timer = setTimeout(() => { - if (typeof fallback === 'function') { - try { - resolve(fallback()); - } catch (err) { - reject(err); + static normalizeOrigin(url, servername) { + if (typeof url === 'string') { + url = new URL(url); + } + + if (servername && url.hostname !== servername) { + url.hostname = servername; + } + + return url.origin; + } + + normalizeOptions(options) { + let normalized = ''; + + if (options) { + for (const key of nameKeys) { + if (options[key]) { + normalized += `:${options[key]}`; + } } - return; } - const message = typeof fallback === 'string' ? fallback : `Promise timed out after ${ms} milliseconds`; - const err = fallback instanceof Error ? fallback : new TimeoutError(message); + return normalized; + } - if (typeof promise.cancel === 'function') { - promise.cancel(); + _tryToCreateNewSession(normalizedOptions, normalizedOrigin) { + if (!(normalizedOptions in this.queue) || !(normalizedOrigin in this.queue[normalizedOptions])) { + return; } - reject(err); - }, ms); + const item = this.queue[normalizedOptions][normalizedOrigin]; - pFinally( - promise.then(resolve, reject), - () => { - clearTimeout(timer); + // The entry function can be run only once. + // BUG: The session may be never created when: + // - the first condition is false AND + // - this function is never called with the same arguments in the future. + if (this._sessionsCount < this.maxSessions && !item.completed) { + item.completed = true; + + item(); } - ); -}); + } -module.exports.TimeoutError = TimeoutError; + getSession(origin, options, listeners) { + return new Promise((resolve, reject) => { + if (Array.isArray(listeners)) { + listeners = [...listeners]; + // Resolve the current promise ASAP, we're just moving the listeners. + // They will be executed at a different time. + resolve(); + } else { + listeners = [{resolve, reject}]; + } -/***/ }), + const normalizedOptions = this.normalizeOptions(options); + const normalizedOrigin = Agent.normalizeOrigin(origin, options && options.servername); -/***/ 668: -/***/ (function(__unusedmodule, exports) { + if (normalizedOrigin === undefined) { + for (const {reject} of listeners) { + reject(new TypeError('The `origin` argument needs to be a string or an URL object')); + } -"use strict"; + return; + } -Object.defineProperty(exports, "__esModule", { value: true }); -// When attaching listeners, it's very easy to forget about them. -// Especially if you do error handling and set timeouts. -// So instead of checking if it's proper to throw an error on every timeout ever, -// use this simple tool which will remove all listeners you have attached. -exports.default = () => { - const handlers = []; - return { - once(origin, event, fn) { - origin.once(event, fn); - handlers.push({ origin, event, fn }); - }, - unhandleAll() { - for (const handler of handlers) { - const { origin, event, fn } = handler; - origin.removeListener(event, fn); - } - handlers.length = 0; - } - }; -}; + if (normalizedOptions in this.sessions) { + const sessions = this.sessions[normalizedOptions]; + let maxConcurrentStreams = -1; + let currentStreamsCount = -1; + let optimalSession; -/***/ }), + // We could just do this.sessions[normalizedOptions].find(...) but that isn't optimal. + // Additionally, we are looking for session which has biggest current pending streams count. + for (const session of sessions) { + const sessionMaxConcurrentStreams = session.remoteSettings.maxConcurrentStreams; -/***/ 669: -/***/ (function(module) { + if (sessionMaxConcurrentStreams < maxConcurrentStreams) { + break; + } -module.exports = require("util"); + if (session[kOriginSet].includes(normalizedOrigin)) { + const sessionCurrentStreamsCount = session[kCurrentStreamsCount]; + + if ( + sessionCurrentStreamsCount >= sessionMaxConcurrentStreams || + session[kGracefullyClosing] || + // Unfortunately the `close` event isn't called immediately, + // so `session.destroyed` is `true`, but `session.closed` is `false`. + session.destroyed + ) { + continue; + } -/***/ }), + // We only need set this once. + if (!optimalSession) { + maxConcurrentStreams = sessionMaxConcurrentStreams; + } -/***/ 676: -/***/ (function(module, __unusedexports, __webpack_require__) { + // We're looking for the session which has biggest current pending stream count, + // in order to minimalize the amount of active sessions. + if (sessionCurrentStreamsCount > currentStreamsCount) { + optimalSession = session; + currentStreamsCount = sessionCurrentStreamsCount; + } + } + } -const auth = __webpack_require__(151); -const secrets = __webpack_require__(461); + if (optimalSession) { + /* istanbul ignore next: safety check */ + if (listeners.length !== 1) { + for (const {reject} of listeners) { + const error = new Error( + `Expected the length of listeners to be 1, got ${listeners.length}.\n` + + 'Please report this to https://github.com/szmarczak/http2-wrapper/' + ); -module.exports = { - auth, - secrets -}; + reject(error); + } -/***/ }), + return; + } -/***/ 678: -/***/ (function(__unusedmodule, exports, __webpack_require__) { + listeners[0].resolve(optimalSession); + return; + } + } -"use strict"; + if (normalizedOptions in this.queue) { + if (normalizedOrigin in this.queue[normalizedOptions]) { + // There's already an item in the queue, just attach ourselves to it. + this.queue[normalizedOptions][normalizedOrigin].listeners.push(...listeners); -Object.defineProperty(exports, "__esModule", { value: true }); -const is_1 = __webpack_require__(534); -const errors_1 = __webpack_require__(378); -const retryAfterStatusCodes = new Set([413, 429, 503]); -const isErrorWithResponse = (error) => (error instanceof errors_1.HTTPError || error instanceof errors_1.ParseError || error instanceof errors_1.MaxRedirectsError); -const calculateRetryDelay = ({ attemptCount, retryOptions, error }) => { - if (attemptCount > retryOptions.limit) { - return 0; - } - const hasMethod = retryOptions.methods.includes(error.options.method); - const hasErrorCode = Reflect.has(error, 'code') && retryOptions.errorCodes.includes(error.code); - const hasStatusCode = isErrorWithResponse(error) && retryOptions.statusCodes.includes(error.response.statusCode); - if (!hasMethod || (!hasErrorCode && !hasStatusCode)) { - return 0; - } - if (isErrorWithResponse(error)) { - const { response } = error; - if (response && Reflect.has(response.headers, 'retry-after') && retryAfterStatusCodes.has(response.statusCode)) { - let after = Number(response.headers['retry-after']); - if (is_1.default.nan(after)) { - after = Date.parse(response.headers['retry-after']) - Date.now(); - } - else { - after *= 1000; - } - if (after > retryOptions.maxRetryAfter) { - return 0; - } - return after; - } - if (response.statusCode === 413) { - return 0; - } - } - const noise = Math.random() * 100; - return ((2 ** (attemptCount - 1)) * 1000) + noise; -}; -exports.default = calculateRetryDelay; + // This shouldn't be executed here. + // See the comment inside _tryToCreateNewSession. + this._tryToCreateNewSession(normalizedOptions, normalizedOrigin); + return; + } + } else { + this.queue[normalizedOptions] = {}; + } + // The entry must be removed from the queue IMMEDIATELY when: + // 1. the session connects successfully, + // 2. an error occurs. + const removeFromQueue = () => { + // Our entry can be replaced. We cannot remove the new one. + if (normalizedOptions in this.queue && this.queue[normalizedOptions][normalizedOrigin] === entry) { + delete this.queue[normalizedOptions][normalizedOrigin]; -/***/ }), + if (Object.keys(this.queue[normalizedOptions]).length === 0) { + delete this.queue[normalizedOptions]; + } + } + }; -/***/ 697: -/***/ (function(module) { + // The main logic is here + const entry = () => { + const name = `${normalizedOrigin}:${normalizedOptions}`; + let receivedSettings = false; -"use strict"; + try { + const session = http2.connect(origin, { + createConnection: this.createConnection, + settings: this.settings, + session: this.tlsSessionCache.get(name), + ...options + }); + session[kCurrentStreamsCount] = 0; + session[kGracefullyClosing] = false; + + const isFree = () => session[kCurrentStreamsCount] < session.remoteSettings.maxConcurrentStreams; + let wasFree = true; + + session.socket.once('session', tlsSession => { + this.tlsSessionCache.set(name, tlsSession); + }); + + session.once('error', error => { + // Listeners are empty when the session successfully connected. + for (const {reject} of listeners) { + reject(error); + } -module.exports = (promise, onFinally) => { - onFinally = onFinally || (() => {}); - - return promise.then( - val => new Promise(resolve => { - resolve(onFinally()); - }).then(() => val), - err => new Promise(resolve => { - resolve(onFinally()); - }).then(() => { - throw err; - }) - ); -}; + // The connection got broken, purge the cache. + this.tlsSessionCache.delete(name); + }); + + session.setTimeout(this.timeout, () => { + // Terminates all streams owned by this session. + // TODO: Maybe the streams should have a "Session timed out" error? + session.destroy(); + }); + + session.once('close', () => { + if (receivedSettings) { + // 1. If it wasn't free then no need to decrease because + // it has been decreased already in session.request(). + // 2. `stream.once('close')` won't increment the count + // because the session is already closed. + if (wasFree) { + this._freeSessionsCount--; + } + this._sessionsCount--; -/***/ }), + // This cannot be moved to the stream logic, + // because there may be a session that hadn't made a single request. + const where = this.sessions[normalizedOptions]; + where.splice(where.indexOf(session), 1); -/***/ 705: -/***/ (function(module, __unusedexports, __webpack_require__) { + if (where.length === 0) { + delete this.sessions[normalizedOptions]; + } + } else { + // Broken connection + const error = new Error('Session closed without receiving a SETTINGS frame'); + error.code = 'HTTP2WRAPPER_NOSETTINGS'; -"use strict"; + for (const {reject} of listeners) { + reject(error); + } -const pump = __webpack_require__(453); -const bufferStream = __webpack_require__(72); + removeFromQueue(); + } -class MaxBufferError extends Error { - constructor() { - super('maxBuffer exceeded'); - this.name = 'MaxBufferError'; - } -} + // There may be another session awaiting. + this._tryToCreateNewSession(normalizedOptions, normalizedOrigin); + }); -async function getStream(inputStream, options) { - if (!inputStream) { - return Promise.reject(new Error('Expected a stream')); - } + // Iterates over the queue and processes listeners. + const processListeners = () => { + if (!(normalizedOptions in this.queue) || !isFree()) { + return; + } - options = { - maxBuffer: Infinity, - ...options - }; + for (const origin of session[kOriginSet]) { + if (origin in this.queue[normalizedOptions]) { + const {listeners} = this.queue[normalizedOptions][origin]; - const {maxBuffer} = options; + // Prevents session overloading. + while (listeners.length !== 0 && isFree()) { + // We assume `resolve(...)` calls `request(...)` *directly*, + // otherwise the session will get overloaded. + listeners.shift().resolve(session); + } - let stream; - await new Promise((resolve, reject) => { - const rejectPromise = error => { - if (error) { // A null check - error.bufferedData = stream.getBufferedValue(); - } + const where = this.queue[normalizedOptions]; + if (where[origin].listeners.length === 0) { + delete where[origin]; - reject(error); - }; + if (Object.keys(where).length === 0) { + delete this.queue[normalizedOptions]; + break; + } + } - stream = pump(inputStream, bufferStream(options), error => { - if (error) { - rejectPromise(error); - return; - } + // We're no longer free, no point in continuing. + if (!isFree()) { + break; + } + } + } + }; - resolve(); - }); + // The Origin Set cannot shrink. No need to check if it suddenly became covered by another one. + session.on('origin', () => { + session[kOriginSet] = session.originSet; - stream.on('data', () => { - if (stream.getBufferedLength() > maxBuffer) { - rejectPromise(new MaxBufferError()); - } - }); - }); + if (!isFree()) { + // The session is full. + return; + } - return stream.getBufferedValue(); -} + processListeners(); -module.exports = getStream; -// TODO: Remove this for the next major release -module.exports.default = getStream; -module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'}); -module.exports.array = (stream, options) => getStream(stream, {...options, array: true}); -module.exports.MaxBufferError = MaxBufferError; + // Close covered sessions (if possible). + closeCoveredSessions(this.sessions[normalizedOptions], session); + }); + + session.once('remoteSettings', () => { + // Fix Node.js bug preventing the process from exiting + session.ref(); + session.unref(); + + this._sessionsCount++; + + // The Agent could have been destroyed already. + if (entry.destroyed) { + const error = new Error('Agent has been destroyed'); + + for (const listener of listeners) { + listener.reject(error); + } + + session.destroy(); + return; + } + + session[kOriginSet] = session.originSet; + + { + const where = this.sessions; + + if (normalizedOptions in where) { + const sessions = where[normalizedOptions]; + sessions.splice(getSortedIndex(sessions, session, compareSessions), 0, session); + } else { + where[normalizedOptions] = [session]; + } + } + + this._freeSessionsCount += 1; + receivedSettings = true; + + this.emit('session', session); + + processListeners(); + removeFromQueue(); + + // TODO: Close last recently used (or least used?) session + if (session[kCurrentStreamsCount] === 0 && this._freeSessionsCount > this.maxFreeSessions) { + session.close(); + } + + // Check if we haven't managed to execute all listeners. + if (listeners.length !== 0) { + // Request for a new session with predefined listeners. + this.getSession(normalizedOrigin, options, listeners); + listeners.length = 0; + } + + // `session.remoteSettings.maxConcurrentStreams` might get increased + session.on('remoteSettings', () => { + processListeners(); + + // In case the Origin Set changes + closeCoveredSessions(this.sessions[normalizedOptions], session); + }); + }); + + // Shim `session.request()` in order to catch all streams + session[kRequest] = session.request; + session.request = (headers, streamOptions) => { + if (session[kGracefullyClosing]) { + throw new Error('The session is gracefully closing. No new streams are allowed.'); + } + + const stream = session[kRequest](headers, streamOptions); + + // The process won't exit until the session is closed or all requests are gone. + session.ref(); + + ++session[kCurrentStreamsCount]; + + if (session[kCurrentStreamsCount] === session.remoteSettings.maxConcurrentStreams) { + this._freeSessionsCount--; + } + stream.once('close', () => { + wasFree = isFree(); -/***/ }), + --session[kCurrentStreamsCount]; -/***/ 718: -/***/ (function(module, __unusedexports, __webpack_require__) { + if (!session.destroyed && !session.closed) { + closeSessionIfCovered(this.sessions[normalizedOptions], session); -"use strict"; + if (isFree() && !session.closed) { + if (!wasFree) { + this._freeSessionsCount++; + wasFree = true; + } -var stream = __webpack_require__(413); + const isEmpty = session[kCurrentStreamsCount] === 0; -function DuplexWrapper(options, writable, readable) { - if (typeof readable === "undefined") { - readable = writable; - writable = options; - options = null; - } + if (isEmpty) { + session.unref(); + } - stream.Duplex.call(this, options); + if ( + isEmpty && + ( + this._freeSessionsCount > this.maxFreeSessions || + session[kGracefullyClosing] + ) + ) { + session.close(); + } else { + closeCoveredSessions(this.sessions[normalizedOptions], session); + processListeners(); + } + } + } + }); - if (typeof readable.read !== "function") { - readable = (new stream.Readable(options)).wrap(readable); - } + return stream; + }; + } catch (error) { + for (const listener of listeners) { + listener.reject(error); + } - this._writable = writable; - this._readable = readable; - this._waiting = false; + removeFromQueue(); + } + }; - var self = this; + entry.listeners = listeners; + entry.completed = false; + entry.destroyed = false; - writable.once("finish", function() { - self.end(); - }); + this.queue[normalizedOptions][normalizedOrigin] = entry; + this._tryToCreateNewSession(normalizedOptions, normalizedOrigin); + }); + } - this.once("finish", function() { - writable.end(); - }); + request(origin, options, headers, streamOptions) { + return new Promise((resolve, reject) => { + this.getSession(origin, options, [{ + reject, + resolve: session => { + try { + resolve(session.request(headers, streamOptions)); + } catch (error) { + reject(error); + } + } + }]); + }); + } - readable.on("readable", function() { - if (self._waiting) { - self._waiting = false; - self._read(); - } - }); + createConnection(origin, options) { + return Agent.connect(origin, options); + } - readable.once("end", function() { - self.push(null); - }); + static connect(origin, options) { + options.ALPNProtocols = ['h2']; - if (!options || typeof options.bubbleErrors === "undefined" || options.bubbleErrors) { - writable.on("error", function(err) { - self.emit("error", err); - }); + const port = origin.port || 443; + const host = origin.hostname || origin.host; - readable.on("error", function(err) { - self.emit("error", err); - }); - } -} + if (typeof options.servername === 'undefined') { + options.servername = host; + } -DuplexWrapper.prototype = Object.create(stream.Duplex.prototype, {constructor: {value: DuplexWrapper}}); + return tls.connect(port, host, options); + } -DuplexWrapper.prototype._write = function _write(input, encoding, done) { - this._writable.write(input, encoding, done); -}; + closeFreeSessions() { + for (const sessions of Object.values(this.sessions)) { + for (const session of sessions) { + if (session[kCurrentStreamsCount] === 0) { + session.close(); + } + } + } + } -DuplexWrapper.prototype._read = function _read() { - var buf; - var reads = 0; - while ((buf = this._readable.read()) !== null) { - this.push(buf); - reads++; - } - if (reads === 0) { - this._waiting = true; - } -}; + destroy(reason) { + for (const sessions of Object.values(this.sessions)) { + for (const session of sessions) { + session.destroy(reason); + } + } -module.exports = function duplex2(options, writable, readable) { - return new DuplexWrapper(options, writable, readable); -}; + for (const entriesOfAuthority of Object.values(this.queue)) { + for (const entry of Object.values(entriesOfAuthority)) { + entry.destroyed = true; + } + } -module.exports.DuplexWrapper = DuplexWrapper; + // New requests should NOT attach to destroyed sessions + this.queue = {}; + } + get freeSessions() { + return getSessions({agent: this, isFree: true}); + } -/***/ }), + get busySessions() { + return getSessions({agent: this, isFree: false}); + } +} -/***/ 747: -/***/ (function(module) { +Agent.kCurrentStreamsCount = kCurrentStreamsCount; +Agent.kGracefullyClosing = kGracefullyClosing; + +module.exports = { + Agent, + globalAgent: new Agent() +}; -module.exports = require("fs"); /***/ }), -/***/ 753: -/***/ (function(module, __unusedexports, __webpack_require__) { +/***/ 904: +/***/ (function(module) { "use strict"; -const {Resolver, V4MAPPED, ADDRCONFIG} = __webpack_require__(881); -const {promisify} = __webpack_require__(669); -const os = __webpack_require__(87); -const Keyv = __webpack_require__(303); - -const kCacheableLookupData = Symbol('cacheableLookupData'); -const kCacheableLookupInstance = Symbol('cacheableLookupInstance'); -const verifyAgent = agent => { - if (!(agent && typeof agent.createConnection === 'function')) { - throw new Error('Expected an Agent instance as the first argument'); - } -}; +class QuickLRU { + constructor(options = {}) { + if (!(options.maxSize && options.maxSize > 0)) { + throw new TypeError('`maxSize` must be a number greater than 0'); + } -const map4to6 = entries => { - for (const entry of entries) { - entry.address = `::ffff:${entry.address}`; - entry.family = 6; + this.maxSize = options.maxSize; + this.onEviction = options.onEviction; + this.cache = new Map(); + this.oldCache = new Map(); + this._size = 0; } -}; -const getIfaceInfo = () => { - let has4 = false; - let has6 = false; + _set(key, value) { + this.cache.set(key, value); + this._size++; - for (const device of Object.values(os.networkInterfaces())) { - for (const iface of device) { - if (iface.internal) { - continue; - } + if (this._size >= this.maxSize) { + this._size = 0; - if (iface.family === 'IPv6') { - has6 = true; - } else { - has4 = true; + if (typeof this.onEviction === 'function') { + for (const [key, value] of this.oldCache.entries()) { + this.onEviction(key, value); + } } - if (has4 && has6) { - break; - } + this.oldCache = this.cache; + this.cache = new Map(); } } - return {has4, has6}; -}; + get(key) { + if (this.cache.has(key)) { + return this.cache.get(key); + } -class CacheableLookup { - constructor({cacheAdapter, maxTtl = Infinity, resolver} = {}) { - this.cache = new Keyv({ - uri: typeof cacheAdapter === 'string' && cacheAdapter, - store: typeof cacheAdapter !== 'string' && cacheAdapter, - namespace: 'cached-lookup' - }); + if (this.oldCache.has(key)) { + const value = this.oldCache.get(key); + this.oldCache.delete(key); + this._set(key, value); + return value; + } + } - this.maxTtl = maxTtl; + set(key, value) { + if (this.cache.has(key)) { + this.cache.set(key, value); + } else { + this._set(key, value); + } - this._resolver = resolver || new Resolver(); - this._resolve4 = promisify(this._resolver.resolve4.bind(this._resolver)); - this._resolve6 = promisify(this._resolver.resolve6.bind(this._resolver)); + return this; + } - this._iface = getIfaceInfo(); + has(key) { + return this.cache.has(key) || this.oldCache.has(key); + } - this.lookup = this.lookup.bind(this); - this.lookupAsync = this.lookupAsync.bind(this); + peek(key) { + if (this.cache.has(key)) { + return this.cache.get(key); + } + + if (this.oldCache.has(key)) { + return this.oldCache.get(key); + } } - set servers(servers) { - this._resolver.setServers(servers); + delete(key) { + const deleted = this.cache.delete(key); + if (deleted) { + this._size--; + } + + return this.oldCache.delete(key) || deleted; } - get servers() { - return this._resolver.getServers(); + clear() { + this.cache.clear(); + this.oldCache.clear(); + this._size = 0; } - lookup(hostname, options, callback) { - if (typeof options === 'function') { - callback = options; - options = {}; + * keys() { + for (const [key] of this) { + yield key; } + } - // eslint-disable-next-line promise/prefer-await-to-then - this.lookupAsync(hostname, {...options, throwNotFound: true}).then(result => { - if (options.all) { - callback(null, result); - } else { - callback(null, result.address, result.family, result.expires, result.ttl); - } - }).catch(callback); + * values() { + for (const [, value] of this) { + yield value; + } } - async lookupAsync(hostname, options = {}) { - let cached; - if (!options.family && options.all) { - const [cached4, cached6] = await Promise.all([this.lookupAsync(hostname, {all: true, family: 4}), this.lookupAsync(hostname, {all: true, family: 6})]); - cached = [...cached4, ...cached6]; - } else { - cached = await this.query(hostname, options.family || 4); + * [Symbol.iterator]() { + for (const item of this.cache) { + yield item; + } - if (cached.length === 0 && options.family === 6 && options.hints & V4MAPPED) { - cached = await this.query(hostname, 4); - map4to6(cached); + for (const item of this.oldCache) { + const [key] = item; + if (!this.cache.has(key)) { + yield item; } } + } - if (options.hints & ADDRCONFIG) { - const {_iface} = this; - cached = cached.filter(entry => entry.family === 6 ? _iface.has6 : _iface.has4); + get size() { + let oldCacheSize = 0; + for (const key of this.oldCache.keys()) { + if (!this.cache.has(key)) { + oldCacheSize++; + } } - if (cached.length === 0 && options.throwNotFound) { - const error = new Error(`ENOTFOUND ${hostname}`); - error.code = 'ENOTFOUND'; - error.hostname = hostname; + return Math.min(this._size + oldCacheSize, this.maxSize); + } +} - throw error; - } +module.exports = QuickLRU; - const now = Date.now(); - cached = cached.filter(entry => entry.ttl === 0 || now < entry.expires); - if (options.all) { - return cached; - } +/***/ }), - if (cached.length === 1) { - return cached[0]; - } +/***/ 907: +/***/ (function(__unusedmodule, exports, __webpack_require__) { - if (cached.length === 0) { - return undefined; - } +"use strict"; - return this._getEntry(cached); - } +Object.defineProperty(exports, "__esModule", { value: true }); +/* istanbul ignore file: deprecated */ +const url_1 = __webpack_require__(835); +const keys = [ + 'protocol', + 'host', + 'hostname', + 'port', + 'pathname', + 'search' +]; +exports.default = (origin, options) => { + var _a, _b; + if (options.path) { + if (options.pathname) { + throw new TypeError('Parameters `path` and `pathname` are mutually exclusive.'); + } + if (options.search) { + throw new TypeError('Parameters `path` and `search` are mutually exclusive.'); + } + if (options.searchParams) { + throw new TypeError('Parameters `path` and `searchParams` are mutually exclusive.'); + } + } + if (options.search && options.searchParams) { + throw new TypeError('Parameters `search` and `searchParams` are mutually exclusive.'); + } + if (!origin) { + if (!options.protocol) { + throw new TypeError('No URL protocol specified'); + } + origin = `${options.protocol}//${(_b = (_a = options.hostname) !== null && _a !== void 0 ? _a : options.host) !== null && _b !== void 0 ? _b : ''}`; + } + const url = new url_1.URL(origin); + if (options.path) { + const searchIndex = options.path.indexOf('?'); + if (searchIndex === -1) { + options.pathname = options.path; + } + else { + options.pathname = options.path.slice(0, searchIndex); + options.search = options.path.slice(searchIndex + 1); + } + delete options.path; + } + for (const key of keys) { + if (options[key]) { + url[key] = options[key].toString(); + } + } + return url; +}; - async query(hostname, family) { - let cached = await this.cache.get(`${hostname}:${family}`); - if (!cached) { - cached = await this.queryAndCache(hostname, family); - } - return cached; - } +/***/ }), - async queryAndCache(hostname, family) { - const resolve = family === 4 ? this._resolve4 : this._resolve6; - const entries = await resolve(hostname, {ttl: true}); +/***/ 910: +/***/ (function(__unusedmodule, exports, __webpack_require__) { - if (entries === undefined) { - return []; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const types_1 = __webpack_require__(36); +function createRejection(error, ...beforeErrorGroups) { + const promise = (async () => { + if (error instanceof types_1.RequestError) { + try { + for (const hooks of beforeErrorGroups) { + if (hooks) { + for (const hook of hooks) { + // eslint-disable-next-line no-await-in-loop + error = await hook(error); + } + } + } + } + catch (error_) { + error = error_; + } + } + throw error; + })(); + const returnPromise = () => promise; + promise.json = returnPromise; + promise.text = returnPromise; + promise.buffer = returnPromise; + promise.on = returnPromise; + return promise; +} +exports.default = createRejection; + + +/***/ }), + +/***/ 927: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const types_1 = __webpack_require__(36); +const retryAfterStatusCodes = new Set([413, 429, 503]); +const isErrorWithResponse = (error) => (error instanceof types_1.HTTPError || error instanceof types_1.ParseError || error instanceof types_1.MaxRedirectsError); +const calculateRetryDelay = ({ attemptCount, retryOptions, error }) => { + if (attemptCount > retryOptions.limit) { + return 0; + } + const hasMethod = retryOptions.methods.includes(error.options.method); + const hasErrorCode = retryOptions.errorCodes.includes(error.code); + const hasStatusCode = isErrorWithResponse(error) && retryOptions.statusCodes.includes(error.response.statusCode); + if (!hasMethod || (!hasErrorCode && !hasStatusCode)) { + return 0; + } + if (isErrorWithResponse(error)) { + const { response } = error; + if (response && 'retry-after' in response.headers && retryAfterStatusCodes.has(response.statusCode)) { + let after = Number(response.headers['retry-after']); + if (Number.isNaN(after)) { + after = Date.parse(response.headers['retry-after']) - Date.now(); + } + else { + after *= 1000; + } + if (retryOptions.maxRetryAfter === undefined || after > retryOptions.maxRetryAfter) { + return 0; + } + return after; + } + if (response.statusCode === 413) { + return 0; + } + } + const noise = Math.random() * 100; + return ((2 ** (attemptCount - 1)) * 1000) + noise; +}; +exports.default = calculateRetryDelay; - const now = Date.now(); - let cacheTtl = 0; - for (const entry of entries) { - cacheTtl = Math.max(cacheTtl, entry.ttl); - entry.family = family; - entry.expires = now + (entry.ttl * 1000); - } +/***/ }), - cacheTtl = Math.min(this.maxTtl, cacheTtl) * 1000; +/***/ 928: +/***/ (function(module, __unusedexports, __webpack_require__) { - if (this.maxTtl !== 0 && cacheTtl !== 0) { - await this.cache.set(`${hostname}:${family}`, entries, cacheTtl); - } +// @ts-check +const core = __webpack_require__(470); +const command = __webpack_require__(431); +const got = __webpack_require__(77).default; +const jsonata = __webpack_require__(350); +const { auth: { retrieveToken }, secrets: { getSecrets } } = __webpack_require__(676); - return entries; - } +const AUTH_METHODS = ['approle', 'token', 'github']; +const VALID_KV_VERSION = [-1, 1, 2]; - _getEntry(entries) { - return entries[Math.floor(Math.random() * entries.length)]; - } +async function exportSecrets() { + const vaultUrl = core.getInput('url', { required: true }); + const vaultNamespace = core.getInput('namespace', { required: false }); + const extraHeaders = parseHeadersInput('extraHeaders', { required: false }); + const exportEnv = core.getInput('exportEnv', { required: false }) != 'false'; - install(agent) { - verifyAgent(agent); + let enginePath = core.getInput('path', { required: false }); + /** @type {number | string} */ + let kvVersion = core.getInput('kv-version', { required: false }); - if (kCacheableLookupData in agent) { - throw new Error('CacheableLookup has been already installed'); - } + const secretsInput = core.getInput('secrets', { required: true }); + const secretRequests = parseSecretsInput(secretsInput); - agent[kCacheableLookupData] = agent.createConnection; - agent[kCacheableLookupInstance] = this; + const vaultMethod = (core.getInput('method', { required: false }) || 'token').toLowerCase(); + const authPayload = core.getInput('authPayload', { required: false }); + if (!AUTH_METHODS.includes(vaultMethod) && !authPayload) { + throw Error(`Sorry, the provided authentication method ${vaultMethod} is not currently supported and no custom authPayload was provided.`); + } - agent.createConnection = (options, callback) => { - if (!('lookup' in options)) { - options.lookup = this.lookup; - } + const defaultOptions = { + prefixUrl: vaultUrl, + headers: {}, + https: {} + } - return agent[kCacheableLookupData](options, callback); - }; - } + const tlsSkipVerify = core.getInput('tlsSkipVerify', { required: false }) != 'false'; + if (tlsSkipVerify == true) { + defaultOptions.https.rejectUnauthorized = true; + } - uninstall(agent) { - verifyAgent(agent); + const caCertificateRaw = core.getInput('caCertificate', { required: false }); + console.log(caCertificateRaw) + if (caCertificateRaw != "" || caCertificateRaw != undefined) { + defaultOptions.https.certificateAuthority = Buffer.from(caCertificateRaw, 'base64'); + } - if (agent[kCacheableLookupData]) { - if (agent[kCacheableLookupInstance] !== this) { - throw new Error('The agent is not owned by this CacheableLookup instance'); - } + console.log(defaultOptions.https.certificateAuthority.toString()) - agent.createConnection = agent[kCacheableLookupData]; + const clientCertificateRaw = core.getInput('clientCertificate', { required: false }); + if (clientCertificateRaw != "") { + defaultOptions.https.certificate = Buffer.from(clientCertificateRaw, 'base64'); + } - delete agent[kCacheableLookupData]; - delete agent[kCacheableLookupInstance]; - } - } + const clientKeyRaw = core.getInput('clientKey', { required: false }); + if (clientKeyRaw != "") { + defaultOptions.https.key = Buffer.from(clientCertificateRaw, 'base64'); + } - updateInterfaceInfo() { - this._iface = getIfaceInfo(); - } -} + for (const [headerName, headerValue] of extraHeaders) { + defaultOptions.headers[headerName] = headerValue; + } -module.exports = CacheableLookup; -module.exports.default = CacheableLookup; + if (vaultNamespace != null) { + defaultOptions.headers["X-Vault-Namespace"] = vaultNamespace; + } + const vaultToken = await retrieveToken(vaultMethod, got.extend(defaultOptions)); + defaultOptions.headers['X-Vault-Token'] = vaultToken; + const client = got.extend(defaultOptions); -/***/ }), + if (!enginePath) { + enginePath = 'secret'; + } -/***/ 761: -/***/ (function(module) { + if (!kvVersion) { + kvVersion = 2; + } + kvVersion = +kvVersion; -module.exports = require("zlib"); + if (Number.isNaN(kvVersion) || !VALID_KV_VERSION.includes(kvVersion)) { + throw Error(`You must provide a valid K/V version (${VALID_KV_VERSION.slice(1).join(', ')}). Input: "${kvVersion}"`); + } -/***/ }), + const requests = secretRequests.map(request => { + const { path, selector } = request; -/***/ 766: -/***/ (function(__unusedmodule, exports) { + if (path.startsWith('/')) { + return request; + } + const kvPath = (kvVersion === 2) + ? `/${enginePath}/data/${path}` + : `/${enginePath}/${path}`; + const kvSelector = (kvVersion === 2) + ? `data.data.${selector}` + : `data.${selector}`; + return { ...request, path: kvPath, selector: kvSelector }; + }); -"use strict"; + const results = await getSecrets(requests, client); -Object.defineProperty(exports, "__esModule", { value: true }); -const knownHookEvents = [ - 'beforeError', - 'init', - 'beforeRequest', - 'beforeRedirect', - 'beforeRetry', - 'afterResponse' -]; -exports.default = knownHookEvents; + for (const result of results) { + const { value, request, cachedResponse } = result; + if (cachedResponse) { + core.debug('ℹ using cached response'); + } + command.issue('add-mask', value); + if (exportEnv) { + core.exportVariable(request.envVarName, `${value}`); + } + core.setOutput(request.outputVarName, `${value}`); + core.debug(`✔ ${request.path} => outputs.${request.outputVarName}${exportEnv ? ` | env.${request.envVarName}` : ''}`); + } +}; +/** @typedef {Object} SecretRequest + * @property {string} path + * @property {string} envVarName + * @property {string} outputVarName + * @property {string} selector +*/ -/***/ }), +/** + * Parses a secrets input string into key paths and their resulting environment variable name. + * @param {string} secretsInput + */ +function parseSecretsInput(secretsInput) { + const secrets = secretsInput + .split(';') + .filter(key => !!key) + .map(key => key.trim()) + .filter(key => key.length !== 0); -/***/ 790: -/***/ (function(module, exports, __webpack_require__) { + /** @type {SecretRequest[]} */ + const output = []; + for (const secret of secrets) { + let pathSpec = secret; + let outputVarName = null; -"use strict"; + const renameSigilIndex = secret.lastIndexOf('|'); + if (renameSigilIndex > -1) { + pathSpec = secret.substring(0, renameSigilIndex).trim(); + outputVarName = secret.substring(renameSigilIndex + 1).trim(); -Object.defineProperty(exports, "__esModule", { value: true }); -const tls_1 = __webpack_require__(818); -const deferToConnect = (socket, fn) => { - let listeners; - if (typeof fn === 'function') { - const connect = fn; - listeners = { connect }; - } - else { - listeners = fn; - } - const hasConnectListener = typeof listeners.connect === 'function'; - const hasSecureConnectListener = typeof listeners.secureConnect === 'function'; - const hasCloseListener = typeof listeners.close === 'function'; - const onConnect = () => { - if (hasConnectListener) { - listeners.connect(); - } - if (socket instanceof tls_1.TLSSocket && hasSecureConnectListener) { - if (socket.authorized) { - listeners.secureConnect(); - } - else if (!socket.authorizationError) { - socket.once('secureConnect', listeners.secureConnect); + if (outputVarName.length < 1) { + throw Error(`You must provide a value when mapping a secret to a name. Input: "${secret}"`); } } - if (hasCloseListener) { - socket.once('close', listeners.close); - } - }; - if (socket.writable && !socket.connecting) { - onConnect(); - } - else if (socket.connecting) { - socket.once('connect', onConnect); - } - else if (socket.destroyed && hasCloseListener) { - listeners.close(socket._hadError); - } -}; -exports.default = deferToConnect; -// For CommonJS default export support -module.exports = deferToConnect; -module.exports.default = deferToConnect; + const pathParts = pathSpec + .split(/\s+/) + .map(part => part.trim()) + .filter(part => part.length !== 0); -/***/ }), - -/***/ 818: -/***/ (function(module) { + if (pathParts.length !== 2) { + throw Error(`You must provide a valid path and key. Input: "${secret}"`); + } -module.exports = require("tls"); + const [path, selector] = pathParts; -/***/ }), + /** @type {any} */ + const selectorAst = jsonata(selector).ast(); -/***/ 835: -/***/ (function(module) { + if ((selectorAst.type !== "path" || selectorAst.steps[0].stages) && !outputVarName) { + throw Error(`You must provide a name for the output key when using json selectors. Input: "${secret}"`); + } -module.exports = require("url"); + let envVarName = outputVarName; + if (!outputVarName) { + outputVarName = normalizeOutputKey(selector); + envVarName = normalizeOutputKey(selector, true); + } -/***/ }), + output.push({ + path, + envVarName, + outputVarName, + selector + }); + } + return output; +} -/***/ 839: -/***/ (function(__unusedmodule, exports) { +/** + * Replaces any dot chars to __ and removes non-ascii charts + * @param {string} dataKey + * @param {boolean=} isEnvVar + */ +function normalizeOutputKey(dataKey, isEnvVar = false) { + let outputKey = dataKey + .replace('.', '__').replace(/[^\p{L}\p{N}_-]/gu, ''); + if (isEnvVar) { + outputKey = outputKey.toUpperCase(); + } + return outputKey; +} -"use strict"; +/** + * @param {string} inputKey + * @param {any} inputOptions + */ +function parseHeadersInput(inputKey, inputOptions) { + /** @type {string}*/ + const rawHeadersString = core.getInput(inputKey, inputOptions) || ''; + const headerStrings = rawHeadersString + .split('\n') + .map(line => line.trim()) + .filter(line => line !== ''); + return headerStrings + .reduce((map, line) => { + const seperator = line.indexOf(':'); + const key = line.substring(0, seperator).trim().toLowerCase(); + const value = line.substring(seperator + 1).trim(); + if (map.has(key)) { + map.set(key, [map.get(key), value].join(', ')); + } else { + map.set(key, value); + } + return map; + }, new Map()); +} -Object.defineProperty(exports, "__esModule", { value: true }); -exports.requestSymbol = Symbol('request'); +module.exports = { + exportSecrets, + parseSecretsInput, + normalizeOutputKey, + parseHeadersInput +}; /***/ }), -/***/ 856: +/***/ 946: /***/ (function(__unusedmodule, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +exports.UnsupportedProtocolError = exports.ReadError = exports.TimeoutError = exports.UploadError = exports.CacheError = exports.HTTPError = exports.MaxRedirectsError = exports.RequestError = exports.setNonEnumerableProperties = exports.knownHookEvents = exports.withoutBody = exports.kIsNormalizedAlready = void 0; +const util_1 = __webpack_require__(669); +const stream_1 = __webpack_require__(413); +const fs_1 = __webpack_require__(747); const url_1 = __webpack_require__(835); -function validateSearchParams(searchParams) { - for (const value of Object.values(searchParams)) { - if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean' && value !== null) { +const http = __webpack_require__(605); +const http_1 = __webpack_require__(605); +const https = __webpack_require__(211); +const http_timer_1 = __webpack_require__(490); +const cacheable_lookup_1 = __webpack_require__(570); +const CacheableRequest = __webpack_require__(390); +const decompressResponse = __webpack_require__(861); +// @ts-expect-error Missing types +const http2wrapper = __webpack_require__(157); +const lowercaseKeys = __webpack_require__(474); +const is_1 = __webpack_require__(534); +const get_body_size_1 = __webpack_require__(786); +const is_form_data_1 = __webpack_require__(460); +const proxy_events_1 = __webpack_require__(628); +const timed_out_1 = __webpack_require__(811); +const url_to_options_1 = __webpack_require__(10); +const options_to_url_1 = __webpack_require__(907); +const weakable_map_1 = __webpack_require__(48); +const get_buffer_1 = __webpack_require__(452); +const dns_ip_version_1 = __webpack_require__(738); +const deprecation_warning_1 = __webpack_require__(189); +const kRequest = Symbol('request'); +const kResponse = Symbol('response'); +const kResponseSize = Symbol('responseSize'); +const kDownloadedSize = Symbol('downloadedSize'); +const kBodySize = Symbol('bodySize'); +const kUploadedSize = Symbol('uploadedSize'); +const kServerResponsesPiped = Symbol('serverResponsesPiped'); +const kUnproxyEvents = Symbol('unproxyEvents'); +const kIsFromCache = Symbol('isFromCache'); +const kCancelTimeouts = Symbol('cancelTimeouts'); +const kStartedReading = Symbol('startedReading'); +const kStopReading = Symbol('stopReading'); +const kTriggerRead = Symbol('triggerRead'); +const kBody = Symbol('body'); +const kJobs = Symbol('jobs'); +const kOriginalResponse = Symbol('originalResponse'); +exports.kIsNormalizedAlready = Symbol('isNormalizedAlready'); +const supportsBrotli = is_1.default.string(process.versions.brotli); +exports.withoutBody = new Set(['GET', 'HEAD']); +exports.knownHookEvents = ['init', 'beforeRequest', 'beforeRedirect', 'beforeError']; +function validateSearchParameters(searchParameters) { + // eslint-disable-next-line guard-for-in + for (const key in searchParameters) { + const value = searchParameters[key]; + if (!is_1.default.string(value) && !is_1.default.number(value) && !is_1.default.boolean(value) && !is_1.default.null_(value) && !is_1.default.undefined(value)) { throw new TypeError(`The \`searchParams\` value '${String(value)}' must be a string, number, boolean or null`); } } } -const keys = [ - 'protocol', - 'username', - 'password', - 'host', - 'hostname', - 'port', - 'pathname', - 'search', - 'hash' +function isClientRequest(clientRequest) { + return is_1.default.object(clientRequest) && !('statusCode' in clientRequest); +} +const cacheableStore = new weakable_map_1.default(); +const waitForOpenFile = async (file) => new Promise((resolve, reject) => { + const onError = (error) => { + reject(error); + }; + // Node.js 12 has incomplete types + if (!file.pending) { + resolve(); + } + file.once('error', onError); + file.once('ready', () => { + file.off('error', onError); + resolve(); + }); +}); +const redirectCodes = new Set([300, 301, 302, 303, 304, 307, 308]); +const nonEnumerableProperties = [ + 'context', + 'body', + 'json', + 'form' ]; -exports.default = (options) => { - var _a, _b; - let origin; - if (options.path) { - if (options.pathname) { - throw new TypeError('Parameters `path` and `pathname` are mutually exclusive.'); +exports.setNonEnumerableProperties = (sources, to) => { + // Non enumerable properties shall not be merged + const properties = {}; + for (const source of sources) { + if (!source) { + continue; } - if (options.search) { - throw new TypeError('Parameters `path` and `search` are mutually exclusive.'); + for (const name of nonEnumerableProperties) { + if (!(name in source)) { + continue; + } + properties[name] = { + writable: true, + configurable: true, + enumerable: false, + // @ts-expect-error TS doesn't see the check above + value: source[name] + }; } - if (options.searchParams) { - throw new TypeError('Parameters `path` and `searchParams` are mutually exclusive.'); + } + Object.defineProperties(to, properties); +}; +class RequestError extends Error { + constructor(message, error, self) { + var _a; + super(message); + Error.captureStackTrace(this, this.constructor); + this.name = 'RequestError'; + this.code = error.code; + if (self instanceof Request) { + Object.defineProperty(this, 'request', { + enumerable: false, + value: self + }); + Object.defineProperty(this, 'response', { + enumerable: false, + value: self[kResponse] + }); + Object.defineProperty(this, 'options', { + // This fails because of TS 3.7.2 useDefineForClassFields + // Ref: https://github.com/microsoft/TypeScript/issues/34972 + enumerable: false, + value: self.options + }); + } + else { + Object.defineProperty(this, 'options', { + // This fails because of TS 3.7.2 useDefineForClassFields + // Ref: https://github.com/microsoft/TypeScript/issues/34972 + enumerable: false, + value: self + }); + } + this.timings = (_a = this.request) === null || _a === void 0 ? void 0 : _a.timings; + // Recover the original stacktrace + if (!is_1.default.undefined(error.stack)) { + const indexOfMessage = this.stack.indexOf(this.message) + this.message.length; + const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse(); + const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message) + error.message.length).split('\n').reverse(); + // Remove duplicated traces + while (errorStackTrace.length !== 0 && errorStackTrace[0] === thisStackTrace[0]) { + thisStackTrace.shift(); + } + this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.reverse().join('\n')}${errorStackTrace.reverse().join('\n')}`; } } - if (Reflect.has(options, 'auth')) { - throw new TypeError('Parameter `auth` is deprecated. Use `username` / `password` instead.'); +} +exports.RequestError = RequestError; +class MaxRedirectsError extends RequestError { + constructor(request) { + super(`Redirected ${request.options.maxRedirects} times. Aborting.`, {}, request); + this.name = 'MaxRedirectsError'; } - if (options.search && options.searchParams) { - throw new TypeError('Parameters `search` and `searchParams` are mutually exclusive.'); +} +exports.MaxRedirectsError = MaxRedirectsError; +class HTTPError extends RequestError { + constructor(response) { + super(`Response code ${response.statusCode} (${response.statusMessage})`, {}, response.request); + this.name = 'HTTPError'; + } +} +exports.HTTPError = HTTPError; +class CacheError extends RequestError { + constructor(error, request) { + super(error.message, error, request); + this.name = 'CacheError'; + } +} +exports.CacheError = CacheError; +class UploadError extends RequestError { + constructor(error, request) { + super(error.message, error, request); + this.name = 'UploadError'; } - if (options.href) { - return new url_1.URL(options.href); +} +exports.UploadError = UploadError; +class TimeoutError extends RequestError { + constructor(error, timings, request) { + super(error.message, error, request); + this.name = 'TimeoutError'; + this.event = error.event; + this.timings = timings; } - if (options.origin) { - origin = options.origin; +} +exports.TimeoutError = TimeoutError; +class ReadError extends RequestError { + constructor(error, request) { + super(error.message, error, request); + this.name = 'ReadError'; } - else { - if (!options.protocol) { - throw new TypeError('No URL protocol specified'); +} +exports.ReadError = ReadError; +class UnsupportedProtocolError extends RequestError { + constructor(options) { + super(`Unsupported protocol "${options.url.protocol}"`, {}, options); + this.name = 'UnsupportedProtocolError'; + } +} +exports.UnsupportedProtocolError = UnsupportedProtocolError; +const proxiedRequestEvents = [ + 'socket', + 'connect', + 'continue', + 'information', + 'upgrade', + 'timeout' +]; +class Request extends stream_1.Duplex { + constructor(url, options = {}, defaults) { + super({ + // It needs to be zero because we're just proxying the data to another stream + highWaterMark: 0 + }); + this[kDownloadedSize] = 0; + this[kUploadedSize] = 0; + this.requestInitialized = false; + this[kServerResponsesPiped] = new Set(); + this.redirects = []; + this[kStopReading] = false; + this[kTriggerRead] = false; + this[kJobs] = []; + // TODO: Remove this when targeting Node.js >= 12 + this._progressCallbacks = []; + const unlockWrite = () => this._unlockWrite(); + const lockWrite = () => this._lockWrite(); + this.on('pipe', (source) => { + source.prependListener('data', unlockWrite); + source.on('data', lockWrite); + source.prependListener('end', unlockWrite); + source.on('end', lockWrite); + }); + this.on('unpipe', (source) => { + source.off('data', unlockWrite); + source.off('data', lockWrite); + source.off('end', unlockWrite); + source.off('end', lockWrite); + }); + this.on('pipe', source => { + if (source instanceof http_1.IncomingMessage) { + this.options.headers = { + ...source.headers, + ...this.options.headers + }; + } + }); + const { json, body, form } = options; + if (json || body || form) { + this._lockWrite(); } - origin = `${options.protocol}//${_b = (_a = options.hostname, (_a !== null && _a !== void 0 ? _a : options.host)), (_b !== null && _b !== void 0 ? _b : '')}`; + (async (nonNormalizedOptions) => { + var _a; + try { + if (nonNormalizedOptions.body instanceof fs_1.ReadStream) { + await waitForOpenFile(nonNormalizedOptions.body); + } + if (exports.kIsNormalizedAlready in nonNormalizedOptions) { + this.options = nonNormalizedOptions; + } + else { + // @ts-expect-error Common TypeScript bug saying that `this.constructor` is not accessible + this.options = this.constructor.normalizeArguments(url, nonNormalizedOptions, defaults); + } + const { url: normalizedURL } = this.options; + if (!normalizedURL) { + throw new TypeError('Missing `url` property'); + } + this.requestUrl = normalizedURL.toString(); + decodeURI(this.requestUrl); + await this._finalizeBody(); + await this._makeRequest(); + if (this.destroyed) { + (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.destroy(); + return; + } + // Queued writes etc. + for (const job of this[kJobs]) { + job(); + } + this.requestInitialized = true; + } + catch (error) { + if (error instanceof RequestError) { + this._beforeError(error); + return; + } + // This is a workaround for https://github.com/nodejs/node/issues/33335 + if (!this.destroyed) { + this.destroy(error); + } + } + })(options); } - const url = new url_1.URL(origin); - if (options.path) { - const searchIndex = options.path.indexOf('?'); - if (searchIndex === -1) { - options.pathname = options.path; + static normalizeArguments(url, options, defaults) { + var _a, _b, _c, _d; + const rawOptions = options; + if (is_1.default.object(url) && !is_1.default.urlInstance(url)) { + options = { ...defaults, ...url, ...options }; } else { - options.pathname = options.path.slice(0, searchIndex); - options.search = options.path.slice(searchIndex + 1); + if (url && options && options.url !== undefined) { + throw new TypeError('The `url` option is mutually exclusive with the `input` argument'); + } + options = { ...defaults, ...options }; + if (url !== undefined) { + options.url = url; + } + if (is_1.default.urlInstance(options.url)) { + options.url = new url_1.URL(options.url.toString()); + } + } + // TODO: Deprecate URL options in Got 12. + // Support extend-specific options + if (options.cache === false) { + options.cache = undefined; + } + if (options.dnsCache === false) { + options.dnsCache = undefined; + } + // Nice type assertions + is_1.assert.any([is_1.default.string, is_1.default.undefined], options.method); + is_1.assert.any([is_1.default.object, is_1.default.undefined], options.headers); + is_1.assert.any([is_1.default.string, is_1.default.urlInstance, is_1.default.undefined], options.prefixUrl); + is_1.assert.any([is_1.default.object, is_1.default.undefined], options.cookieJar); + is_1.assert.any([is_1.default.object, is_1.default.string, is_1.default.undefined], options.searchParams); + is_1.assert.any([is_1.default.object, is_1.default.string, is_1.default.undefined], options.cache); + is_1.assert.any([is_1.default.object, is_1.default.number, is_1.default.undefined], options.timeout); + is_1.assert.any([is_1.default.object, is_1.default.undefined], options.context); + is_1.assert.any([is_1.default.object, is_1.default.undefined], options.hooks); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.decompress); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.ignoreInvalidCookies); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.followRedirect); + is_1.assert.any([is_1.default.number, is_1.default.undefined], options.maxRedirects); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.throwHttpErrors); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.http2); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.allowGetBody); + is_1.assert.any([is_1.default.string, is_1.default.undefined], options.localAddress); + is_1.assert.any([dns_ip_version_1.isDnsLookupIpVersion, is_1.default.undefined], options.dnsLookupIpVersion); + is_1.assert.any([is_1.default.object, is_1.default.undefined], options.https); + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.rejectUnauthorized); + if (options.https) { + is_1.assert.any([is_1.default.boolean, is_1.default.undefined], options.https.rejectUnauthorized); + is_1.assert.any([is_1.default.function_, is_1.default.undefined], options.https.checkServerIdentity); + is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificateAuthority); + is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.key); + is_1.assert.any([is_1.default.string, is_1.default.object, is_1.default.array, is_1.default.undefined], options.https.certificate); + is_1.assert.any([is_1.default.string, is_1.default.undefined], options.https.passphrase); + } + // `options.method` + if (is_1.default.string(options.method)) { + options.method = options.method.toUpperCase(); } - } - if (Reflect.has(options, 'path')) { - delete options.path; - } - for (const key of keys) { - if (Reflect.has(options, key)) { - url[key] = options[key].toString(); + else { + options.method = 'GET'; } - } - if (options.searchParams) { - if (typeof options.searchParams !== 'string' && !(options.searchParams instanceof url_1.URLSearchParams)) { - validateSearchParams(options.searchParams); + // `options.headers` + if (options.headers === (defaults === null || defaults === void 0 ? void 0 : defaults.headers)) { + options.headers = { ...options.headers }; } - (new url_1.URLSearchParams(options.searchParams)).forEach((value, key) => { - url.searchParams.append(key, value); - }); - } - return url; -}; - - -/***/ }), - -/***/ 861: -/***/ (function(module, __unusedexports, __webpack_require__) { - -"use strict"; - -const { - pipeline: streamPipeline, - PassThrough: PassThroughStream -} = __webpack_require__(413); -const zlib = __webpack_require__(761); -const mimicResponse = __webpack_require__(89); - -const decompressResponse = response => { - const contentEncoding = (response.headers['content-encoding'] || '').toLowerCase(); - - if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) { - return response; - } - - // TODO: Remove this when targeting Node.js 12. - const isBrotli = contentEncoding === 'br'; - if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') { - return response; - } - - const decompress = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip(); - const stream = new PassThroughStream(); - - decompress.on('error', error => { - // Ignore empty response - if (error.code === 'Z_BUF_ERROR') { - stream.end(); - return; - } - - stream.emit('error', error); - }); - - const finalStream = streamPipeline(response, decompress, stream, () => {}); - - mimicResponse(response, finalStream); - - return finalStream; -}; - -module.exports = decompressResponse; - - -/***/ }), - -/***/ 872: -/***/ (function(__unusedmodule, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs_1 = __webpack_require__(747); -const CacheableRequest = __webpack_require__(946); -const EventEmitter = __webpack_require__(614); -const http = __webpack_require__(605); -const stream = __webpack_require__(413); -const url_1 = __webpack_require__(835); -const util_1 = __webpack_require__(669); -const is_1 = __webpack_require__(534); -const http_timer_1 = __webpack_require__(490); -const calculate_retry_delay_1 = __webpack_require__(678); -const errors_1 = __webpack_require__(378); -const get_response_1 = __webpack_require__(234); -const normalize_arguments_1 = __webpack_require__(110); -const progress_1 = __webpack_require__(489); -const timed_out_1 = __webpack_require__(215); -const types_1 = __webpack_require__(839); -const url_to_options_1 = __webpack_require__(278); -const pEvent = __webpack_require__(148); -const setImmediateAsync = async () => new Promise(resolve => setImmediate(resolve)); -const pipeline = util_1.promisify(stream.pipeline); -const redirectCodes = new Set([300, 301, 302, 303, 304, 307, 308]); -exports.default = (options) => { - const emitter = new EventEmitter(); - const requestUrl = options.url.toString(); - const redirects = []; - let retryCount = 0; - let currentRequest; - // `request.aborted` is a boolean since v11.0.0: https://github.com/nodejs/node/commit/4b00c4fafaa2ae8c41c1f78823c0feb810ae4723#diff-e3bc37430eb078ccbafe3aa3b570c91a - const isAborted = () => typeof currentRequest.aborted === 'number' || currentRequest.aborted; - const emitError = async (error) => { - try { - for (const hook of options.hooks.beforeError) { - // eslint-disable-next-line no-await-in-loop - error = await hook(error); + else { + options.headers = lowercaseKeys({ ...(defaults === null || defaults === void 0 ? void 0 : defaults.headers), ...options.headers }); + } + // Disallow legacy `url.Url` + if ('slashes' in options) { + throw new TypeError('The legacy `url.Url` has been deprecated. Use `URL` instead.'); + } + // `options.auth` + if ('auth' in options) { + throw new TypeError('Parameter `auth` is deprecated. Use `username` / `password` instead.'); + } + // `options.searchParams` + if ('searchParams' in options) { + if (options.searchParams && options.searchParams !== (defaults === null || defaults === void 0 ? void 0 : defaults.searchParams)) { + let searchParameters; + if (is_1.default.string(options.searchParams) || (options.searchParams instanceof url_1.URLSearchParams)) { + searchParameters = new url_1.URLSearchParams(options.searchParams); + } + else { + validateSearchParameters(options.searchParams); + searchParameters = new url_1.URLSearchParams(); + // eslint-disable-next-line guard-for-in + for (const key in options.searchParams) { + const value = options.searchParams[key]; + if (value === null) { + searchParameters.append(key, ''); + } + else if (value !== undefined) { + searchParameters.append(key, value); + } + } + } + // `normalizeArguments()` is also used to merge options + (_a = defaults === null || defaults === void 0 ? void 0 : defaults.searchParams) === null || _a === void 0 ? void 0 : _a.forEach((value, key) => { + // Only use default if one isn't already defined + if (!searchParameters.has(key)) { + searchParameters.append(key, value); + } + }); + options.searchParams = searchParameters; + } + } + // `options.username` & `options.password` + options.username = (_b = options.username) !== null && _b !== void 0 ? _b : ''; + options.password = (_c = options.password) !== null && _c !== void 0 ? _c : ''; + // `options.prefixUrl` & `options.url` + if (options.prefixUrl) { + options.prefixUrl = options.prefixUrl.toString(); + if (options.prefixUrl !== '' && !options.prefixUrl.endsWith('/')) { + options.prefixUrl += '/'; + } + } + else { + options.prefixUrl = ''; + } + if (is_1.default.string(options.url)) { + if (options.url.startsWith('/')) { + throw new Error('`input` must not start with a slash when using `prefixUrl`'); + } + options.url = options_to_url_1.default(options.prefixUrl + options.url, options); + } + else if ((is_1.default.undefined(options.url) && options.prefixUrl !== '') || options.protocol) { + options.url = options_to_url_1.default(options.prefixUrl, options); + } + if (options.url) { + // Make it possible to change `options.prefixUrl` + let { prefixUrl } = options; + Object.defineProperty(options, 'prefixUrl', { + set: (value) => { + const url = options.url; + if (!url.href.startsWith(value)) { + throw new Error(`Cannot change \`prefixUrl\` from ${prefixUrl} to ${value}: ${url.href}`); + } + options.url = new url_1.URL(value + url.href.slice(prefixUrl.length)); + prefixUrl = value; + }, + get: () => prefixUrl + }); + // Support UNIX sockets + let { protocol } = options.url; + if (protocol === 'unix:') { + protocol = 'http:'; + options.url = new url_1.URL(`http://unix${options.url.pathname}${options.url.search}`); + } + // Set search params + if (options.searchParams) { + // eslint-disable-next-line @typescript-eslint/no-base-to-string + options.url.search = options.searchParams.toString(); + } + // Protocol check + if (protocol !== 'http:' && protocol !== 'https:') { + throw new UnsupportedProtocolError(options); + } + // Update `username` + if (options.username === '') { + options.username = options.url.username; + } + else { + options.url.username = options.username; + } + // Update `password` + if (options.password === '') { + options.password = options.url.password; + } + else { + options.url.password = options.password; } - emitter.emit('error', error); } - catch (error_) { - emitter.emit('error', error_); + // `options.cookieJar` + const { cookieJar } = options; + if (cookieJar) { + let { setCookie, getCookieString } = cookieJar; + is_1.assert.function_(setCookie); + is_1.assert.function_(getCookieString); + /* istanbul ignore next: Horrible `tough-cookie` v3 check */ + if (setCookie.length === 4 && getCookieString.length === 0) { + setCookie = util_1.promisify(setCookie.bind(options.cookieJar)); + getCookieString = util_1.promisify(getCookieString.bind(options.cookieJar)); + options.cookieJar = { + setCookie, + // TODO: Fix this when upgrading to TypeScript 4. + // @ts-expect-error TypeScript thinks that promisifying callback(error, string) will result in Promise + getCookieString + }; + } } - }; - const get = async () => { - let httpOptions = await normalize_arguments_1.normalizeRequestArguments(options); - const handleResponse = async (response) => { - var _a; - try { - /* istanbul ignore next: fixes https://github.com/electron/electron/blob/cbb460d47628a7a146adf4419ed48550a98b2923/lib/browser/api/net.js#L59-L65 */ - if (options.useElectronNet) { - response = new Proxy(response, { - get: (target, name) => { - if (name === 'trailers' || name === 'rawTrailers') { - return []; + // `options.cache` + const { cache } = options; + if (cache) { + if (!cacheableStore.has(cache)) { + cacheableStore.set(cache, new CacheableRequest(((requestOptions, handler) => { + const result = requestOptions[kRequest](requestOptions, handler); + // TODO: remove this when `cacheable-request` supports async request functions. + if (is_1.default.promise(result)) { + // @ts-expect-error + // We only need to implement the error handler in order to support HTTP2 caching. + // The result will be a promise anyway. + result.once = (event, handler) => { + if (event === 'error') { + result.catch(handler); } - const value = target[name]; - return is_1.default.function_(value) ? value.bind(target) : value; - } - }); - } - const typedResponse = response; - const { statusCode } = typedResponse; - typedResponse.statusMessage = is_1.default.nonEmptyString(typedResponse.statusMessage) ? typedResponse.statusMessage : http.STATUS_CODES[statusCode]; - typedResponse.url = options.url.toString(); - typedResponse.requestUrl = requestUrl; - typedResponse.retryCount = retryCount; - typedResponse.redirectUrls = redirects; - typedResponse.request = { options }; - typedResponse.isFromCache = (_a = typedResponse.fromCache, (_a !== null && _a !== void 0 ? _a : false)); - delete typedResponse.fromCache; - if (!typedResponse.isFromCache) { - typedResponse.ip = response.socket.remoteAddress; - } - const rawCookies = typedResponse.headers['set-cookie']; - if (Reflect.has(options, 'cookieJar') && rawCookies) { - let promises = rawCookies.map(async (rawCookie) => options.cookieJar.setCookie(rawCookie, typedResponse.url)); - if (options.ignoreInvalidCookies) { - promises = promises.map(async (p) => p.catch(() => { })); + else if (event === 'abort') { + // The empty catch is needed here in case when + // it rejects before it's `await`ed in `_makeRequest`. + (async () => { + try { + const request = (await result); + request.once('abort', handler); + } + catch (_a) { } + })(); + } + else { + /* istanbul ignore next: safety check */ + throw new Error(`Unknown HTTP2 promise event: ${event}`); + } + return result; + }; } - await Promise.all(promises); - } - if (options.followRedirect && Reflect.has(typedResponse.headers, 'location') && redirectCodes.has(statusCode)) { - typedResponse.resume(); // We're being redirected, we don't care about the response. - // eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare - if (statusCode === 303 || options.methodRewriting === false) { - if (options.method !== 'GET' && options.method !== 'HEAD') { - // Server responded with "see other", indicating that the resource exists at another location, - // and the client should request it from that location via GET or HEAD. - options.method = 'GET'; - } - if (Reflect.has(options, 'body')) { - delete options.body; - } - if (Reflect.has(options, 'json')) { - delete options.json; - } - if (Reflect.has(options, 'form')) { - delete options.form; - } + return result; + }), cache)); + } + } + // `options.dnsCache` + if (options.dnsCache === true) { + options.dnsCache = new cacheable_lookup_1.default(); + } + else if (!is_1.default.undefined(options.dnsCache) && !options.dnsCache.lookup) { + throw new TypeError(`Parameter \`dnsCache\` must be a CacheableLookup instance or a boolean, got ${is_1.default(options.dnsCache)}`); + } + // `options.timeout` + if (is_1.default.number(options.timeout)) { + options.timeout = { request: options.timeout }; + } + else if (defaults && options.timeout !== defaults.timeout) { + options.timeout = { + ...defaults.timeout, + ...options.timeout + }; + } + else { + options.timeout = { ...options.timeout }; + } + // `options.context` + if (!options.context) { + options.context = {}; + } + // `options.hooks` + const areHooksDefault = options.hooks === (defaults === null || defaults === void 0 ? void 0 : defaults.hooks); + options.hooks = { ...options.hooks }; + for (const event of exports.knownHookEvents) { + if (event in options.hooks) { + if (is_1.default.array(options.hooks[event])) { + // See https://github.com/microsoft/TypeScript/issues/31445#issuecomment-576929044 + options.hooks[event] = [...options.hooks[event]]; + } + else { + throw new TypeError(`Parameter \`${event}\` must be an Array, got ${is_1.default(options.hooks[event])}`); + } + } + else { + options.hooks[event] = []; + } + } + if (defaults && !areHooksDefault) { + for (const event of exports.knownHookEvents) { + const defaultHooks = defaults.hooks[event]; + if (defaultHooks.length !== 0) { + // See https://github.com/microsoft/TypeScript/issues/31445#issuecomment-576929044 + options.hooks[event] = [ + ...defaults.hooks[event], + ...options.hooks[event] + ]; + } + } + } + // DNS options + if ('family' in options) { + deprecation_warning_1.default('"options.family" was never documented, please use "options.dnsLookupIpVersion"'); + } + // HTTPS options + if (defaults === null || defaults === void 0 ? void 0 : defaults.https) { + options.https = { ...defaults.https, ...options.https }; + } + if ('rejectUnauthorized' in options) { + deprecation_warning_1.default('"options.rejectUnauthorized" is now deprecated, please use "options.https.rejectUnauthorized"'); + } + if ('checkServerIdentity' in options) { + deprecation_warning_1.default('"options.checkServerIdentity" was never documented, please use "options.https.checkServerIdentity"'); + } + if ('ca' in options) { + deprecation_warning_1.default('"options.ca" was never documented, please use "options.https.certificateAuthority"'); + } + if ('key' in options) { + deprecation_warning_1.default('"options.key" was never documented, please use "options.https.key"'); + } + if ('cert' in options) { + deprecation_warning_1.default('"options.cert" was never documented, please use "options.https.certificate"'); + } + if ('passphrase' in options) { + deprecation_warning_1.default('"options.passphrase" was never documented, please use "options.https.passphrase"'); + } + // Other options + if ('followRedirects' in options) { + throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.'); + } + if (options.agent) { + for (const key in options.agent) { + if (key !== 'http' && key !== 'https' && key !== 'http2') { + throw new TypeError(`Expected the \`options.agent\` properties to be \`http\`, \`https\` or \`http2\`, got \`${key}\``); + } + } + } + options.maxRedirects = (_d = options.maxRedirects) !== null && _d !== void 0 ? _d : 0; + // Set non-enumerable properties + exports.setNonEnumerableProperties([defaults, rawOptions], options); + return options; + } + _lockWrite() { + const onLockedWrite = () => { + throw new TypeError('The payload has been already provided'); + }; + this.write = onLockedWrite; + this.end = onLockedWrite; + } + _unlockWrite() { + this.write = super.write; + this.end = super.end; + } + async _finalizeBody() { + const { options } = this; + const { headers } = options; + const isForm = !is_1.default.undefined(options.form); + const isJSON = !is_1.default.undefined(options.json); + const isBody = !is_1.default.undefined(options.body); + const hasPayload = isForm || isJSON || isBody; + const cannotHaveBody = exports.withoutBody.has(options.method) && !(options.method === 'GET' && options.allowGetBody); + this._cannotHaveBody = cannotHaveBody; + if (hasPayload) { + if (cannotHaveBody) { + throw new TypeError(`The \`${options.method}\` method cannot be used with a body`); + } + if ([isBody, isForm, isJSON].filter(isTrue => isTrue).length > 1) { + throw new TypeError('The `body`, `json` and `form` options are mutually exclusive'); + } + if (isBody && + !(options.body instanceof stream_1.Readable) && + !is_1.default.string(options.body) && + !is_1.default.buffer(options.body) && + !is_form_data_1.default(options.body)) { + throw new TypeError('The `body` option must be a stream.Readable, string or Buffer'); + } + if (isForm && !is_1.default.object(options.form)) { + throw new TypeError('The `form` option must be an Object'); + } + { + // Serialize body + const noContentType = !is_1.default.string(headers['content-type']); + if (isBody) { + // Special case for https://github.com/form-data/form-data + if (is_form_data_1.default(options.body) && noContentType) { + headers['content-type'] = `multipart/form-data; boundary=${options.body.getBoundary()}`; } - if (redirects.length >= options.maxRedirects) { - throw new errors_1.MaxRedirectsError(typedResponse, options.maxRedirects, options); + this[kBody] = options.body; + } + else if (isForm) { + if (noContentType) { + headers['content-type'] = 'application/x-www-form-urlencoded'; } - // Handles invalid URLs. See https://github.com/sindresorhus/got/issues/604 - const redirectBuffer = Buffer.from(typedResponse.headers.location, 'binary').toString(); - const redirectUrl = new url_1.URL(redirectBuffer, options.url); - // Redirecting to a different site, clear cookies. - if (redirectUrl.hostname !== options.url.hostname && Reflect.has(options.headers, 'cookie')) { - delete options.headers.cookie; + this[kBody] = (new url_1.URLSearchParams(options.form)).toString(); + } + else { + if (noContentType) { + headers['content-type'] = 'application/json'; } - redirects.push(redirectUrl.toString()); - options.url = redirectUrl; - for (const hook of options.hooks.beforeRedirect) { - // eslint-disable-next-line no-await-in-loop - await hook(options, typedResponse); + this[kBody] = options.stringifyJson(options.json); + } + const uploadBodySize = await get_body_size_1.default(this[kBody], options.headers); + // See https://tools.ietf.org/html/rfc7230#section-3.3.2 + // A user agent SHOULD send a Content-Length in a request message when + // no Transfer-Encoding is sent and the request method defines a meaning + // for an enclosed payload body. For example, a Content-Length header + // field is normally sent in a POST request even when the value is 0 + // (indicating an empty payload body). A user agent SHOULD NOT send a + // Content-Length header field when the request message does not contain + // a payload body and the method semantics do not anticipate such a + // body. + if (is_1.default.undefined(headers['content-length']) && is_1.default.undefined(headers['transfer-encoding'])) { + if (!cannotHaveBody && !is_1.default.undefined(uploadBodySize)) { + headers['content-length'] = String(uploadBodySize); } - emitter.emit('redirect', response, options); - await get(); - return; } - await get_response_1.default(typedResponse, options, emitter); + } + } + else if (cannotHaveBody) { + this._lockWrite(); + } + else { + this._unlockWrite(); + } + this[kBodySize] = Number(headers['content-length']) || undefined; + } + async _onResponseBase(response) { + const { options } = this; + const { url } = options; + this[kOriginalResponse] = response; + if (options.decompress) { + response = decompressResponse(response); + } + const statusCode = response.statusCode; + const typedResponse = response; + typedResponse.statusMessage = typedResponse.statusMessage ? typedResponse.statusMessage : http.STATUS_CODES[statusCode]; + typedResponse.url = options.url.toString(); + typedResponse.requestUrl = this.requestUrl; + typedResponse.redirectUrls = this.redirects; + typedResponse.request = this; + typedResponse.isFromCache = response.fromCache || false; + typedResponse.ip = this.ip; + this[kIsFromCache] = typedResponse.isFromCache; + this[kResponseSize] = Number(response.headers['content-length']) || undefined; + this[kResponse] = response; + response.once('end', () => { + this[kResponseSize] = this[kDownloadedSize]; + this.emit('downloadProgress', this.downloadProgress); + }); + response.once('error', (error) => { + // Force clean-up, because some packages don't do this. + // TODO: Fix decompress-response + response.destroy(); + this._beforeError(new ReadError(error, this)); + }); + response.once('aborted', () => { + this._beforeError(new ReadError({ + name: 'Error', + message: 'The server aborted pending request', + code: 'ECONNRESET' + }, this)); + }); + this.emit('downloadProgress', this.downloadProgress); + const rawCookies = response.headers['set-cookie']; + if (is_1.default.object(options.cookieJar) && rawCookies) { + let promises = rawCookies.map(async (rawCookie) => options.cookieJar.setCookie(rawCookie, url.toString())); + if (options.ignoreInvalidCookies) { + promises = promises.map(async (p) => p.catch(() => { })); + } + try { + await Promise.all(promises); } catch (error) { - emitError(error); + this._beforeError(error); + return; } - }; - const handleRequest = async (request) => { - let isPiped = false; - let isFinished = false; - // `request.finished` doesn't indicate whether this has been emitted or not - request.once('finish', () => { - isFinished = true; - }); - currentRequest = request; - const onError = (error) => { - if (error instanceof timed_out_1.TimeoutError) { - error = new errors_1.TimeoutError(error, request.timings, options); + } + if (options.followRedirect && response.headers.location && redirectCodes.has(statusCode)) { + // We're being redirected, we don't care about the response. + // It'd be besto to abort the request, but we can't because + // we would have to sacrifice the TCP connection. We don't want that. + response.resume(); + if (this[kRequest]) { + this[kCancelTimeouts](); + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this[kRequest]; + this[kUnproxyEvents](); + } + const shouldBeGet = statusCode === 303 && options.method !== 'GET' && options.method !== 'HEAD'; + if (shouldBeGet || !options.methodRewriting) { + // Server responded with "see other", indicating that the resource exists at another location, + // and the client should request it from that location via GET or HEAD. + options.method = 'GET'; + if ('body' in options) { + delete options.body; } - else { - error = new errors_1.RequestError(error, options); + if ('json' in options) { + delete options.json; } - if (!emitter.retry(error)) { - emitError(error); + if ('form' in options) { + delete options.form; } - }; - request.on('error', error => { - if (isPiped) { - // Check if it's caught by `stream.pipeline(...)` - if (!isFinished) { - return; + } + if (this.redirects.length >= options.maxRedirects) { + this._beforeError(new MaxRedirectsError(this)); + return; + } + try { + // Do not remove. See https://github.com/sindresorhus/got/pull/214 + const redirectBuffer = Buffer.from(response.headers.location, 'binary').toString(); + // Handles invalid URLs. See https://github.com/sindresorhus/got/issues/604 + const redirectUrl = new url_1.URL(redirectBuffer, url); + const redirectString = redirectUrl.toString(); + decodeURI(redirectString); + // Redirecting to a different site, clear sensitive data. + if (redirectUrl.hostname !== url.hostname) { + if ('host' in options.headers) { + delete options.headers.host; } - // We need to let `TimedOutTimeoutError` through, because `stream.pipeline(…)` aborts the request automatically. - if (isAborted() && !(error instanceof timed_out_1.TimeoutError)) { - return; + if ('cookie' in options.headers) { + delete options.headers.cookie; + } + if ('authorization' in options.headers) { + delete options.headers.authorization; + } + if (options.username || options.password) { + delete options.username; + delete options.password; } } - onError(error); - }); - try { - http_timer_1.default(request); - timed_out_1.default(request, options.timeout, options.url); - emitter.emit('request', request); - const uploadStream = progress_1.createProgressStream('uploadProgress', emitter, httpOptions.headers['content-length']); - isPiped = true; - await pipeline(httpOptions.body, uploadStream, request); - request.emit('upload-complete'); + this.redirects.push(redirectString); + options.url = redirectUrl; + for (const hook of options.hooks.beforeRedirect) { + // eslint-disable-next-line no-await-in-loop + await hook(options, typedResponse); + } + this.emit('redirect', typedResponse, options); + await this._makeRequest(); } catch (error) { - if (isAborted() && error.message === 'Premature close') { - // The request was aborted on purpose - return; - } - onError(error); + this._beforeError(error); + return; } - }; - if (options.cache) { - // `cacheable-request` doesn't support Node 10 API, fallback. - httpOptions = { - ...httpOptions, - ...url_to_options_1.default(options.url) - }; - // @ts-ignore `cacheable-request` has got invalid types - const cacheRequest = options.cacheableRequest(httpOptions, handleResponse); - cacheRequest.once('error', (error) => { - if (error instanceof CacheableRequest.RequestError) { - emitError(new errors_1.RequestError(error, options)); - } - else { - emitError(new errors_1.CacheError(error, options)); + return; + } + const limitStatusCode = options.followRedirect ? 299 : 399; + const isOk = (statusCode >= 200 && statusCode <= limitStatusCode) || statusCode === 304; + if (options.throwHttpErrors && !isOk) { + // Normally we would have to use `void [await] this._beforeError(error)` everywhere, + // but since there's `void (async () => { ... })()` inside of it, we don't have to. + this._beforeError(new HTTPError(typedResponse)); + // This is equivalent to this.destroyed + if (this[kStopReading]) { + return; + } + } + response.on('readable', () => { + if (this[kTriggerRead]) { + this._read(); + } + }); + this.on('resume', () => { + response.resume(); + }); + this.on('pause', () => { + response.pause(); + }); + response.once('end', () => { + this.push(null); + }); + this.emit('response', response); + for (const destination of this[kServerResponsesPiped]) { + if (destination.headersSent) { + continue; + } + // eslint-disable-next-line guard-for-in + for (const key in response.headers) { + const isAllowed = options.decompress ? key !== 'content-encoding' : true; + const value = response.headers[key]; + if (isAllowed) { + destination.setHeader(key, value); } + } + destination.statusCode = statusCode; + } + } + async _onResponse(response) { + try { + await this._onResponseBase(response); + } + catch (error) { + this._beforeError(error); + } + } + _onRequest(request) { + const { options } = this; + const { timeout, url } = options; + http_timer_1.default(request); + this[kCancelTimeouts] = timed_out_1.default(request, timeout, url); + const responseEventName = options.cache ? 'cacheableResponse' : 'response'; + request.once(responseEventName, (response) => { + void this._onResponse(response); + }); + request.once('error', (error) => { + var _a; + // Force clean-up, because some packages (e.g. nock) don't do this. + request.destroy(); + // Node.js <= 12.18.2 mistakenly emits the response `end` first. + (_a = request.res) === null || _a === void 0 ? void 0 : _a.removeAllListeners('end'); + if (error instanceof timed_out_1.TimeoutError) { + error = new TimeoutError(error, this.timings, this); + } + else { + error = new RequestError(error.message, error, this); + } + this._beforeError(error); + }); + this[kUnproxyEvents] = proxy_events_1.default(request, this, proxiedRequestEvents); + this[kRequest] = request; + this.emit('uploadProgress', this.uploadProgress); + // Send body + const body = this[kBody]; + const currentRequest = this.redirects.length === 0 ? this : request; + if (is_1.default.nodeStream(body)) { + body.pipe(currentRequest); + body.once('error', (error) => { + this._beforeError(new UploadError(error, this)); + }); + body.once('end', () => { + delete options.body; }); - cacheRequest.once('request', handleRequest); } else { - // Catches errors thrown by calling `requestFn(…)` - try { - handleRequest(httpOptions[types_1.requestSymbol](options.url, httpOptions, handleResponse)); + this._unlockWrite(); + if (!is_1.default.undefined(body)) { + this._writeRequest(body, undefined, () => { }); + currentRequest.end(); + this._lockWrite(); + } + else if (this._cannotHaveBody || this._noPipe) { + currentRequest.end(); + this._lockWrite(); + } + } + this.emit('request', request); + } + async _createCacheableRequest(url, options) { + return new Promise((resolve, reject) => { + // TODO: Remove `utils/url-to-options.ts` when `cacheable-request` is fixed + Object.assign(options, url_to_options_1.default(url)); + // `http-cache-semantics` checks this + delete options.url; + let request; + // This is ugly + const cacheRequest = cacheableStore.get(options.cache)(options, async (response) => { + // TODO: Fix `cacheable-response` + response._readableState.autoDestroy = false; + if (request) { + (await request).emit('cacheableResponse', response); + } + resolve(response); + }); + // Restore options + options.url = url; + cacheRequest.once('error', reject); + cacheRequest.once('request', async (requestOrPromise) => { + request = requestOrPromise; + resolve(request); + }); + }); + } + async _makeRequest() { + var _a; + const { options } = this; + const { headers } = options; + for (const key in headers) { + if (is_1.default.undefined(headers[key])) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete headers[key]; } - catch (error) { - emitError(new errors_1.RequestError(error, options)); + else if (is_1.default.null_(headers[key])) { + throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`); } } - }; - emitter.retry = error => { - let backoff; - retryCount++; - try { - backoff = options.retry.calculateDelay({ - attemptCount: retryCount, - retryOptions: options.retry, - error, - computedValue: calculate_retry_delay_1.default({ - attemptCount: retryCount, - retryOptions: options.retry, - error, - computedValue: 0 - }) - }); + if (options.decompress && is_1.default.undefined(headers['accept-encoding'])) { + headers['accept-encoding'] = supportsBrotli ? 'gzip, deflate, br' : 'gzip, deflate'; } - catch (error_) { - emitError(error_); - return false; + // Set cookies + if (options.cookieJar) { + const cookieString = await options.cookieJar.getCookieString(options.url.toString()); + if (is_1.default.nonEmptyString(cookieString)) { + options.headers.cookie = cookieString; + } } - if (backoff) { - const retry = async (options) => { - try { - for (const hook of options.hooks.beforeRetry) { - // eslint-disable-next-line no-await-in-loop - await hook(options, error, retryCount); - } - await get(); - } - catch (error_) { - emitError(error_); - } - }; - setTimeout(retry, backoff, { ...options, forceRefresh: true }); - return true; + for (const hook of options.hooks.beforeRequest) { + // eslint-disable-next-line no-await-in-loop + const result = await hook(options); + if (!is_1.default.undefined(result)) { + // @ts-expect-error Skip the type mismatch to support abstract responses + options.request = () => result; + break; + } } - return false; - }; - emitter.abort = () => { - emitter.prependListener('request', (request) => { - request.abort(); - }); - if (currentRequest) { - currentRequest.abort(); + const { agent, request, timeout, url } = options; + if (options.dnsCache && !('lookup' in options)) { + options.lookup = options.dnsCache.lookup; + } + // UNIX sockets + if (url.hostname === 'unix') { + const matches = /(?.+?):(?.+)/.exec(`${url.pathname}${url.search}`); + if (matches === null || matches === void 0 ? void 0 : matches.groups) { + const { socketPath, path } = matches.groups; + Object.assign(options, { + socketPath, + path, + host: '' + }); + } + } + const isHttps = url.protocol === 'https:'; + // Fallback function + let fallbackFn; + if (options.http2) { + fallbackFn = http2wrapper.auto; + } + else { + fallbackFn = isHttps ? https.request : http.request; + } + const realFn = (_a = options.request) !== null && _a !== void 0 ? _a : fallbackFn; + // Cache support + const fn = options.cache ? this._createCacheableRequest : realFn; + // Pass an agent directly when HTTP2 is disabled + if (agent && !options.http2) { + options.agent = agent[isHttps ? 'https' : 'http']; + } + // Prepare plain HTTP request options + options[kRequest] = realFn; + delete options.request; + delete options.timeout; + const requestOptions = options; + // If `dnsLookupIpVersion` is not present do not override `family` + if (options.dnsLookupIpVersion !== undefined) { + try { + requestOptions.family = dns_ip_version_1.dnsLookupIpVersionToFamily(options.dnsLookupIpVersion); + } + catch (_b) { + throw new Error('Invalid `dnsLookupIpVersion` option value'); + } + } + // HTTPS options remapping + if (options.https) { + if ('rejectUnauthorized' in options.https) { + requestOptions.rejectUnauthorized = options.https.rejectUnauthorized; + } + if (options.https.checkServerIdentity) { + requestOptions.checkServerIdentity = options.https.checkServerIdentity; + } + if (options.https.certificateAuthority) { + requestOptions.ca = options.https.certificateAuthority; + } + if (options.https.certificate) { + requestOptions.cert = options.https.certificate; + } + if (options.https.key) { + requestOptions.key = options.https.key; + } + if (options.https.passphrase) { + requestOptions.passphrase = options.https.passphrase; + } } - }; - (async () => { try { - if (options.body instanceof fs_1.ReadStream) { - await pEvent(options.body, 'open'); - } - // Promises are executed immediately. - // If there were no `setImmediate` here, - // `promise.json()` would have no effect - // as the request would be sent already. - await setImmediateAsync(); - for (const hook of options.hooks.beforeRequest) { - // eslint-disable-next-line no-await-in-loop - await hook(options); + let requestOrResponse = await fn(url, requestOptions); + if (is_1.default.undefined(requestOrResponse)) { + requestOrResponse = fallbackFn(url, requestOptions); + } + // Restore options + options.request = request; + options.timeout = timeout; + options.agent = agent; + if (isClientRequest(requestOrResponse)) { + this._onRequest(requestOrResponse); + // Emit the response after the stream has been ended + } + else if (this.writable) { + this.once('finish', () => { + void this._onResponse(requestOrResponse); + }); + this._unlockWrite(); + this.end(); + this._lockWrite(); + } + else { + void this._onResponse(requestOrResponse); } - await get(); } catch (error) { - emitError(error); + if (error instanceof CacheableRequest.CacheError) { + throw new CacheError(error, this); + } + throw new RequestError(error.message, error, this); } - })(); - return emitter; -}; -exports.proxyEvents = (proxy, emitter) => { - const events = [ - 'request', - 'redirect', - 'uploadProgress', - 'downloadProgress' - ]; - for (const event of events) { - emitter.on(event, (...args) => { - proxy.emit(event, ...args); - }); } -}; - - -/***/ }), - -/***/ 881: -/***/ (function(module) { - -module.exports = require("dns"); - -/***/ }), - -/***/ 928: -/***/ (function(module, __unusedexports, __webpack_require__) { - -// @ts-check -const core = __webpack_require__(470); -const command = __webpack_require__(431); -const got = __webpack_require__(77).default; -const jsonata = __webpack_require__(350); -const { auth: { retrieveToken }, secrets: { getSecrets } } = __webpack_require__(676); - -const AUTH_METHODS = ['approle', 'token', 'github']; -const VALID_KV_VERSION = [-1, 1, 2]; - -async function exportSecrets() { - const vaultUrl = core.getInput('url', { required: true }); - const vaultNamespace = core.getInput('namespace', { required: false }); - const extraHeaders = parseHeadersInput('extraHeaders', { required: false }); - const exportEnv = core.getInput('exportEnv', { required: false }) != 'false'; - - let enginePath = core.getInput('path', { required: false }); - /** @type {number | string} */ - let kvVersion = core.getInput('kv-version', { required: false }); - - const secretsInput = core.getInput('secrets', { required: true }); - const secretRequests = parseSecretsInput(secretsInput); - - const vaultMethod = (core.getInput('method', { required: false }) || 'token').toLowerCase(); - const authPayload = core.getInput('authPayload', { required: false }); - if (!AUTH_METHODS.includes(vaultMethod) && !authPayload) { - throw Error(`Sorry, the provided authentication method ${vaultMethod} is not currently supported and no custom authPayload was provided.`); + _beforeError(error) { + if (this.destroyed) { + return; + } + this[kStopReading] = true; + if (!(error instanceof RequestError)) { + error = new RequestError(error.message, error, this); + } + void (async () => { + try { + const { response } = error; + if (response) { + response.setEncoding(this._readableState.encoding); + response.rawBody = await get_buffer_1.default(response); + response.body = response.rawBody.toString(); + } + } + catch (_a) { } + try { + for (const hook of this.options.hooks.beforeError) { + // eslint-disable-next-line no-await-in-loop + error = await hook(error); + } + } + catch (error_) { + error = new RequestError(error_.message, error_, this); + } + this.destroy(error); + })(); } - - const defaultOptions = { - prefixUrl: vaultUrl, - headers: {} + _read() { + this[kTriggerRead] = true; + const response = this[kResponse]; + if (response && !this[kStopReading]) { + // We cannot put this in the `if` above + // because `.read()` also triggers the `end` event + if (response.readableLength) { + this[kTriggerRead] = false; + } + let data; + while ((data = response.read()) !== null) { + this[kDownloadedSize] += data.length; + this[kStartedReading] = true; + const progress = this.downloadProgress; + if (progress.percent < 1) { + this.emit('downloadProgress', progress); + } + this.push(data); + } + } + } + // Node.js 12 has incorrect types, so the encoding must be a string + _write(chunk, encoding, callback) { + const write = () => { + this._writeRequest(chunk, encoding, callback); + }; + if (this.requestInitialized) { + write(); + } + else { + this[kJobs].push(write); + } } - - for (const [headerName, headerValue] of extraHeaders) { - defaultOptions.headers[headerName] = headerValue; + _writeRequest(chunk, encoding, callback) { + this._progressCallbacks.push(() => { + this[kUploadedSize] += Buffer.byteLength(chunk, encoding); + const progress = this.uploadProgress; + if (progress.percent < 1) { + this.emit('uploadProgress', progress); + } + }); + // TODO: What happens if it's from cache? Then this[kRequest] won't be defined. + this[kRequest].write(chunk, encoding, (error) => { + if (!error && this._progressCallbacks.length !== 0) { + this._progressCallbacks.shift()(); + } + callback(error); + }); } - - if (vaultNamespace != null) { - defaultOptions.headers["X-Vault-Namespace"] = vaultNamespace; + _final(callback) { + const endRequest = () => { + // FIX: Node.js 10 calls the write callback AFTER the end callback! + while (this._progressCallbacks.length !== 0) { + this._progressCallbacks.shift()(); + } + // We need to check if `this[kRequest]` is present, + // because it isn't when we use cache. + if (!(kRequest in this)) { + callback(); + return; + } + if (this[kRequest].destroyed) { + callback(); + return; + } + this[kRequest].end((error) => { + if (!error) { + this[kBodySize] = this[kUploadedSize]; + this.emit('uploadProgress', this.uploadProgress); + this[kRequest].emit('upload-complete'); + } + callback(error); + }); + }; + if (this.requestInitialized) { + endRequest(); + } + else { + this[kJobs].push(endRequest); + } } - - const vaultToken = await retrieveToken(vaultMethod, got.extend(defaultOptions)); - defaultOptions.headers['X-Vault-Token'] = vaultToken; - const client = got.extend(defaultOptions); - - if (!enginePath) { - enginePath = 'secret'; + _destroy(error, callback) { + var _a; + this[kStopReading] = true; + if (kRequest in this) { + this[kCancelTimeouts](); + // TODO: Remove the next `if` when these get fixed: + // - https://github.com/nodejs/node/issues/32851 + if (!((_a = this[kResponse]) === null || _a === void 0 ? void 0 : _a.complete)) { + this[kRequest].destroy(); + } + } + if (error !== null && !is_1.default.undefined(error) && !(error instanceof RequestError)) { + error = new RequestError(error.message, error, this); + } + callback(error); } - - if (!kvVersion) { - kvVersion = 2; + get ip() { + var _a; + return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket.remoteAddress; } - kvVersion = +kvVersion; - - if (Number.isNaN(kvVersion) || !VALID_KV_VERSION.includes(kvVersion)) { - throw Error(`You must provide a valid K/V version (${VALID_KV_VERSION.slice(1).join(', ')}). Input: "${kvVersion}"`); + get aborted() { + var _a, _b, _c; + return ((_b = (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.destroyed) !== null && _b !== void 0 ? _b : this.destroyed) && !((_c = this[kOriginalResponse]) === null || _c === void 0 ? void 0 : _c.complete); } - - const requests = secretRequests.map(request => { - const { path, selector } = request; - - if (path.startsWith('/')) { - return request; + get socket() { + var _a; + return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.socket; + } + get downloadProgress() { + let percent; + if (this[kResponseSize]) { + percent = this[kDownloadedSize] / this[kResponseSize]; } - const kvPath = (kvVersion === 2) - ? `/${enginePath}/data/${path}` - : `/${enginePath}/${path}`; - const kvSelector = (kvVersion === 2) - ? `data.data.${selector}` - : `data.${selector}`; - return { ...request, path: kvPath, selector: kvSelector }; - }); - - const results = await getSecrets(requests, client); - - for (const result of results) { - const { value, request, cachedResponse } = result; - if (cachedResponse) { - core.debug('ℹ using cached response'); - } - command.issue('add-mask', value); - if (exportEnv) { - core.exportVariable(request.envVarName, `${value}`); + else if (this[kResponseSize] === this[kDownloadedSize]) { + percent = 1; } - core.setOutput(request.outputVarName, `${value}`); - core.debug(`✔ ${request.path} => outputs.${request.outputVarName}${exportEnv ? ` | env.${request.envVarName}` : ''}`); + else { + percent = 0; + } + return { + percent, + transferred: this[kDownloadedSize], + total: this[kResponseSize] + }; } -}; - -/** @typedef {Object} SecretRequest - * @property {string} path - * @property {string} envVarName - * @property {string} outputVarName - * @property {string} selector -*/ - -/** - * Parses a secrets input string into key paths and their resulting environment variable name. - * @param {string} secretsInput - */ -function parseSecretsInput(secretsInput) { - const secrets = secretsInput - .split(';') - .filter(key => !!key) - .map(key => key.trim()) - .filter(key => key.length !== 0); - - /** @type {SecretRequest[]} */ - const output = []; - for (const secret of secrets) { - let pathSpec = secret; - let outputVarName = null; - - const renameSigilIndex = secret.lastIndexOf('|'); - if (renameSigilIndex > -1) { - pathSpec = secret.substring(0, renameSigilIndex).trim(); - outputVarName = secret.substring(renameSigilIndex + 1).trim(); - - if (outputVarName.length < 1) { - throw Error(`You must provide a value when mapping a secret to a name. Input: "${secret}"`); - } + get uploadProgress() { + let percent; + if (this[kBodySize]) { + percent = this[kUploadedSize] / this[kBodySize]; } - - const pathParts = pathSpec - .split(/\s+/) - .map(part => part.trim()) - .filter(part => part.length !== 0); - - if (pathParts.length !== 2) { - throw Error(`You must provide a valid path and key. Input: "${secret}"`); + else if (this[kBodySize] === this[kUploadedSize]) { + percent = 1; } - - const [path, selector] = pathParts; - - /** @type {any} */ - const selectorAst = jsonata(selector).ast(); - - if ((selectorAst.type !== "path" || selectorAst.steps[0].stages) && !outputVarName) { - throw Error(`You must provide a name for the output key when using json selectors. Input: "${secret}"`); + else { + percent = 0; } - - let envVarName = outputVarName; - if (!outputVarName) { - outputVarName = normalizeOutputKey(selector); - envVarName = normalizeOutputKey(selector, true); + return { + percent, + transferred: this[kUploadedSize], + total: this[kBodySize] + }; + } + get timings() { + var _a; + return (_a = this[kRequest]) === null || _a === void 0 ? void 0 : _a.timings; + } + get isFromCache() { + return this[kIsFromCache]; + } + get _response() { + return this[kResponse]; + } + pipe(destination, options) { + if (this[kStartedReading]) { + throw new Error('Failed to pipe. The response has been emitted already.'); } - - output.push({ - path, - envVarName, - outputVarName, - selector - }); + if (destination instanceof http_1.ServerResponse) { + this[kServerResponsesPiped].add(destination); + } + return super.pipe(destination, options); } - return output; -} - -/** - * Replaces any dot chars to __ and removes non-ascii charts - * @param {string} dataKey - * @param {boolean=} isEnvVar - */ -function normalizeOutputKey(dataKey, isEnvVar = false) { - let outputKey = dataKey - .replace('.', '__').replace(/[^\p{L}\p{N}_-]/gu, ''); - if (isEnvVar) { - outputKey = outputKey.toUpperCase(); + unpipe(destination) { + if (destination instanceof http_1.ServerResponse) { + this[kServerResponsesPiped].delete(destination); + } + super.unpipe(destination); + return this; } - return outputKey; -} - -/** - * @param {string} inputKey - * @param {any} inputOptions - */ -function parseHeadersInput(inputKey, inputOptions) { - /** @type {string}*/ - const rawHeadersString = core.getInput(inputKey, inputOptions) || ''; - const headerStrings = rawHeadersString - .split('\n') - .map(line => line.trim()) - .filter(line => line !== ''); - return headerStrings - .reduce((map, line) => { - const seperator = line.indexOf(':'); - const key = line.substring(0, seperator).trim().toLowerCase(); - const value = line.substring(seperator + 1).trim(); - if (map.has(key)) { - map.set(key, [map.get(key), value].join(', ')); - } else { - map.set(key, value); - } - return map; - }, new Map()); } +exports.default = Request; -module.exports = { - exportSecrets, - parseSecretsInput, - normalizeOutputKey, - parseHeadersInput -}; - -/***/ }), - -/***/ 946: -/***/ (function(module, __unusedexports, __webpack_require__) { - -"use strict"; - - -const EventEmitter = __webpack_require__(614); -const urlLib = __webpack_require__(835); -const normalizeUrl = __webpack_require__(53); -const getStream = __webpack_require__(16); -const CachePolicy = __webpack_require__(154); -const Response = __webpack_require__(93); -const lowercaseKeys = __webpack_require__(474); -const cloneResponse = __webpack_require__(325); -const Keyv = __webpack_require__(303); - -class CacheableRequest { - constructor(request, cacheAdapter) { - if (typeof request !== 'function') { - throw new TypeError('Parameter `request` must be a function'); - } - - this.cache = new Keyv({ - uri: typeof cacheAdapter === 'string' && cacheAdapter, - store: typeof cacheAdapter !== 'string' && cacheAdapter, - namespace: 'cacheable-request' - }); - - return this.createCacheableRequest(request); - } - - createCacheableRequest(request) { - return (opts, cb) => { - let url; - if (typeof opts === 'string') { - url = normalizeUrlObject(urlLib.parse(opts)); - opts = {}; - } else if (opts instanceof urlLib.URL) { - url = normalizeUrlObject(urlLib.parse(opts.toString())); - opts = {}; - } else { - const [pathname, ...searchParts] = (opts.path || '').split('?'); - const search = searchParts.length > 0 ? - `?${searchParts.join('?')}` : - ''; - url = normalizeUrlObject({ ...opts, pathname, search }); - } - - opts = { - headers: {}, - method: 'GET', - cache: true, - strictTtl: false, - automaticFailover: false, - ...opts, - ...urlObjectToRequestOptions(url) - }; - opts.headers = lowercaseKeys(opts.headers); - - const ee = new EventEmitter(); - const normalizedUrlString = normalizeUrl( - urlLib.format(url), - { - stripWWW: false, - removeTrailingSlash: false, - stripAuthentication: false - } - ); - const key = `${opts.method}:${normalizedUrlString}`; - let revalidate = false; - let madeRequest = false; - const makeRequest = opts => { - madeRequest = true; - let requestErrored = false; - let requestErrorCallback; +/***/ }), - const requestErrorPromise = new Promise(resolve => { - requestErrorCallback = () => { - if (!requestErrored) { - requestErrored = true; - resolve(); - } - }; - }); +/***/ 988: +/***/ (function(module, __unusedexports, __webpack_require__) { - const handler = response => { - if (revalidate && !opts.forceRefresh) { - response.status = response.statusCode; - const revalidatedPolicy = CachePolicy.fromObject(revalidate.cachePolicy).revalidatedPolicy(opts, response); - if (!revalidatedPolicy.modified) { - const headers = revalidatedPolicy.policy.responseHeaders(); - response = new Response(revalidate.statusCode, headers, revalidate.body, revalidate.url); - response.cachePolicy = revalidatedPolicy.policy; - response.fromCache = true; - } - } +"use strict"; - if (!response.fromCache) { - response.cachePolicy = new CachePolicy(opts, response, opts); - response.fromCache = false; - } +const http = __webpack_require__(605); +const https = __webpack_require__(211); +const resolveALPN = __webpack_require__(524); +const QuickLRU = __webpack_require__(904); +const Http2ClientRequest = __webpack_require__(181); +const calculateServerName = __webpack_require__(751); +const urlToOptions = __webpack_require__(507); - let clonedResponse; - if (opts.cache && response.cachePolicy.storable()) { - clonedResponse = cloneResponse(response); +const cache = new QuickLRU({maxSize: 100}); +const queue = new Map(); - (async () => { - try { - const bodyPromise = getStream.buffer(response); +const installSocket = (agent, socket, options) => { + socket._httpMessage = {shouldKeepAlive: true}; - await Promise.race([ - requestErrorPromise, - new Promise(resolve => response.once('end', resolve)) - ]); + const onFree = () => { + agent.emit('free', socket, options); + }; - if (requestErrored) { - return; - } + socket.on('free', onFree); - const body = await bodyPromise; + const onClose = () => { + agent.removeSocket(socket, options); + }; - const value = { - cachePolicy: response.cachePolicy.toObject(), - url: response.url, - statusCode: response.fromCache ? revalidate.statusCode : response.statusCode, - body - }; + socket.on('close', onClose); - let ttl = opts.strictTtl ? response.cachePolicy.timeToLive() : undefined; - if (opts.maxTtl) { - ttl = ttl ? Math.min(ttl, opts.maxTtl) : opts.maxTtl; - } + const onRemove = () => { + agent.removeSocket(socket, options); + socket.off('close', onClose); + socket.off('free', onFree); + socket.off('agentRemove', onRemove); + }; - await this.cache.set(key, value, ttl); - } catch (error) { - ee.emit('error', new CacheableRequest.CacheError(error)); - } - })(); - } else if (opts.cache && revalidate) { - (async () => { - try { - await this.cache.delete(key); - } catch (error) { - ee.emit('error', new CacheableRequest.CacheError(error)); - } - })(); - } + socket.on('agentRemove', onRemove); - ee.emit('response', clonedResponse || response); - if (typeof cb === 'function') { - cb(clonedResponse || response); - } - }; + agent.emit('free', socket, options); +}; - try { - const req = request(opts, handler); - req.once('error', requestErrorCallback); - req.once('abort', requestErrorCallback); - ee.emit('request', req); - } catch (error) { - ee.emit('error', new CacheableRequest.RequestError(error)); - } - }; +const resolveProtocol = async options => { + const name = `${options.host}:${options.port}:${options.ALPNProtocols.sort()}`; - (async () => { - const get = async opts => { - await Promise.resolve(); + if (!cache.has(name)) { + if (queue.has(name)) { + const result = await queue.get(name); + return result.alpnProtocol; + } - const cacheEntry = opts.cache ? await this.cache.get(key) : undefined; - if (typeof cacheEntry === 'undefined') { - return makeRequest(opts); - } + const {path, agent} = options; + options.path = options.socketPath; - const policy = CachePolicy.fromObject(cacheEntry.cachePolicy); - if (policy.satisfiesWithoutRevalidation(opts) && !opts.forceRefresh) { - const headers = policy.responseHeaders(); - const response = new Response(cacheEntry.statusCode, headers, cacheEntry.body, cacheEntry.url); - response.cachePolicy = policy; - response.fromCache = true; + const resultPromise = resolveALPN(options); + queue.set(name, resultPromise); - ee.emit('response', response); - if (typeof cb === 'function') { - cb(response); - } + try { + const {socket, alpnProtocol} = await resultPromise; + cache.set(name, alpnProtocol); + + options.path = path; + + if (alpnProtocol === 'h2') { + // https://github.com/nodejs/node/issues/33343 + socket.destroy(); + } else { + const {globalAgent} = https; + const defaultCreateConnection = https.Agent.prototype.createConnection; + + if (agent) { + if (agent.createConnection === defaultCreateConnection) { + installSocket(agent, socket, options); } else { - revalidate = cacheEntry; - opts.headers = policy.revalidationHeaders(opts); - makeRequest(opts); + socket.destroy(); } - }; + } else if (globalAgent.createConnection === defaultCreateConnection) { + installSocket(globalAgent, socket, options); + } else { + socket.destroy(); + } + } - const errorHandler = error => ee.emit('error', new CacheableRequest.CacheError(error)); - this.cache.once('error', errorHandler); - ee.on('response', () => this.cache.removeListener('error', errorHandler)); + queue.delete(name); - try { - await get(opts); - } catch (error) { - if (opts.automaticFailover && !madeRequest) { - makeRequest(opts); - } + return alpnProtocol; + } catch (error) { + queue.delete(name); - ee.emit('error', new CacheableRequest.CacheError(error)); - } - })(); + throw error; + } + } - return ee; - }; + return cache.get(name); +}; + +module.exports = async (input, options, callback) => { + if (typeof input === 'string' || input instanceof URL) { + input = urlToOptions(new URL(input)); } -} -function urlObjectToRequestOptions(url) { - const options = { ...url }; - options.path = `${url.pathname || '/'}${url.search || ''}`; - delete options.pathname; - delete options.search; - return options; -} + if (typeof options === 'function') { + callback = options; + options = undefined; + } -function normalizeUrlObject(url) { - // If url was parsed by url.parse or new URL: - // - hostname will be set - // - host will be hostname[:port] - // - port will be set if it was explicit in the parsed string - // Otherwise, url was from request options: - // - hostname or host may be set - // - host shall not have port encoded - return { - protocol: url.protocol, - auth: url.auth, - hostname: url.hostname || url.host || 'localhost', - port: url.port, - pathname: url.pathname, - search: url.search + options = { + ALPNProtocols: ['h2', 'http/1.1'], + ...input, + ...options, + resolveSocket: true }; -} -CacheableRequest.RequestError = class extends Error { - constructor(error) { - super(error.message); - this.name = 'RequestError'; - Object.assign(this, error); + if (!Array.isArray(options.ALPNProtocols) || options.ALPNProtocols.length === 0) { + throw new Error('The `ALPNProtocols` option must be an Array with at least one entry'); } -}; -CacheableRequest.CacheError = class extends Error { - constructor(error) { - super(error.message); - this.name = 'CacheError'; - Object.assign(this, error); + options.protocol = options.protocol || 'https:'; + const isHttps = options.protocol === 'https:'; + + options.host = options.hostname || options.host || 'localhost'; + options.session = options.tlsSession; + options.servername = options.servername || calculateServerName(options); + options.port = options.port || (isHttps ? 443 : 80); + options._defaultAgent = isHttps ? https.globalAgent : http.globalAgent; + + const agents = options.agent; + + if (agents) { + if (agents.addRequest) { + throw new Error('The `options.agent` object can contain only `http`, `https` or `http2` properties'); + } + + options.agent = agents[isHttps ? 'https' : 'http']; + } + + if (isHttps) { + const protocol = await resolveProtocol(options); + + if (protocol === 'h2') { + if (agents) { + options.agent = agents.http2; + } + + return new Http2ClientRequest(options, callback); + } } + + return http.request(options, callback); }; -module.exports = CacheableRequest; +module.exports.protocolCache = cache; /***/ }), -/***/ 952: +/***/ 997: /***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; -const {Readable: ReadableStream} = __webpack_require__(413); +const pump = __webpack_require__(453); +const bufferStream = __webpack_require__(375); -const toReadableStream = input => ( - new ReadableStream({ - read() { - this.push(input); - this.push(null); - } - }) -); +class MaxBufferError extends Error { + constructor() { + super('maxBuffer exceeded'); + this.name = 'MaxBufferError'; + } +} + +async function getStream(inputStream, options) { + if (!inputStream) { + return Promise.reject(new Error('Expected a stream')); + } + + options = { + maxBuffer: Infinity, + ...options + }; + + const {maxBuffer} = options; + + let stream; + await new Promise((resolve, reject) => { + const rejectPromise = error => { + if (error) { // A null check + error.bufferedData = stream.getBufferedValue(); + } + + reject(error); + }; + + stream = pump(inputStream, bufferStream(options), error => { + if (error) { + rejectPromise(error); + return; + } + + resolve(); + }); + + stream.on('data', () => { + if (stream.getBufferedLength() > maxBuffer) { + rejectPromise(new MaxBufferError()); + } + }); + }); + + return stream.getBufferedValue(); +} -module.exports = toReadableStream; +module.exports = getStream; // TODO: Remove this for the next major release -module.exports.default = toReadableStream; +module.exports.default = getStream; +module.exports.buffer = (stream, options) => getStream(stream, {...options, encoding: 'buffer'}); +module.exports.array = (stream, options) => getStream(stream, {...options, array: true}); +module.exports.MaxBufferError = MaxBufferError; /***/ }) -/******/ }, -/******/ function(__webpack_require__) { // webpackRuntimeModules -/******/ "use strict"; -/******/ -/******/ /* webpack/runtime/node module decorator */ -/******/ !function() { -/******/ __webpack_require__.nmd = function(module) { -/******/ module.paths = []; -/******/ if (!module.children) module.children = []; -/******/ Object.defineProperty(module, 'loaded', { -/******/ enumerable: true, -/******/ get: function() { return module.l; } -/******/ }); -/******/ Object.defineProperty(module, 'id', { -/******/ enumerable: true, -/******/ get: function() { return module.i; } -/******/ }); -/******/ return module; -/******/ }; -/******/ }(); -/******/ -/******/ } -); \ No newline at end of file +/******/ }); \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index bc5de24a..4342ebcf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,16 +2,31 @@ version: "3.0" services: vault: - image: vault:1.3.0 + image: vault:latest environment: VAULT_DEV_ROOT_TOKEN_ID: testtoken ports: - 8200:8200 privileged: true vault-enterprise: - image: hashicorp/vault-enterprise:1.3.0_ent + image: hashicorp/vault-enterprise:latest environment: VAULT_DEV_ROOT_TOKEN_ID: testtoken ports: - - 8201:8200 - privileged: true \ No newline at end of file + - 8200:8200 + privileged: true + vault-tls: + image: vault:latest + hostname: vault-tls + environment: + VAULT_CAPATH: /etc/vault/ca.crt + ports: + - 8200:8200 + privileged: true + volumes: + - ${PWD}/integrationTests/e2e-tls/configs:/etc/vault + - vault-data:/var/lib/vault:rw + entrypoint: vault server -config=/etc/vault/config.hcl + +volumes: + vault-data: diff --git a/integrationTests/e2e-tls/README.md b/integrationTests/e2e-tls/README.md new file mode 100644 index 00000000..f7c319c5 --- /dev/null +++ b/integrationTests/e2e-tls/README.md @@ -0,0 +1,4 @@ +# e2e tests + +This test suite runs `vault-action` as a GitHub Action in the context of a live build, and then verifies that the appropriate environmental variables are set. +These tests are intended to mostly be very simple smoke tests to verify that the action is being compiled and run correctly in context. diff --git a/integrationTests/e2e-tls/configs/ca.crt b/integrationTests/e2e-tls/configs/ca.crt new file mode 100644 index 00000000..45244f8f --- /dev/null +++ b/integrationTests/e2e-tls/configs/ca.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFjCCAv6gAwIBAgIUe0i7/HGZKvbDb30L9mC99KXFwj8wDQYJKoZIhvcNAQEL +BQAwgaIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH +Ew1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKEwlIYXNoaUNvcnAxIzAhBgNVBAsTGlRl +c3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MS0wKwYDVQQDEyRQcm90b3R5cGUgVGVz +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMjAwODA1MTg1MjAwWhcNMjUwODA0 +MTg1MjAwWjCBojELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAU +BgNVBAcTDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoTCUhhc2hpQ29ycDEjMCEGA1UE +CxMaVGVzdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxLTArBgNVBAMTJFByb3RvdHlw +ZSBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMrRXuu2+zhBs0pLYEdXIaPc4KoWO3xm2RJdbzy3hfjFybQ8 +H/Y6Hi7txjGGSb45xSfXT/RF2srNfs235I+sfB8rrEizNpzkXqOgGa8LKvh2tgBT +BK/jDWsEdDhxmkpFhE69wEW+D5ub7QGnx9jrqLKfwCmUA0utlzcFBk2nRNhRtsrp +CI5YL1VN4coLpgXdvbodzbynPzGHe9R/o9K0Uiz2hgHooyKwhkVYwo0BIAQamLFz +TS7lyeLf0thDOxV31NX8SpSucqRf50WHNk8T/YtKZ9EhlBDT4ybZwwvcC/ocxxcg +1LvB0YweZNjSeO78S4CMh1TFGXnF/xOtGABlIbcCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFABD/NxvYLpo5zVNeD01 +r8IIFYlBMA0GCSqGSIb3DQEBCwUAA4IBAQB7TfpIx53gf/oI3mgR6Ciz287WBzFR +OzhJXwHk5J3mx8VC1W8tDRXih2lCLd/f9qDy6LyL/hZcoonev6w9oReuOMBiH6l4 +Pf3yq2aDXX0AoGgm75c1m34kY669JLMsHq5+xuUDeeFUMd60w9zVtZfBSumy/sgN +PdjtvThh8sSByocYULs3tuxZDGyQ6GyQcn/xlMrGtmcD5IuX5IXqcKRVlZttykNx +S2ltcR00fekw8WZyPSzMJaP+/Kcq3T2viN02MS6qEycQZoYfEAMdj+A0kjbsZG9D +6J92z78b2DuLAUvZVpynNk/UbpDeqIDy40V3JDmtvrfGUMkMhMqgK/+J +-----END CERTIFICATE----- diff --git a/integrationTests/e2e-tls/configs/client.crt b/integrationTests/e2e-tls/configs/client.crt new file mode 100644 index 00000000..a62e1d21 --- /dev/null +++ b/integrationTests/e2e-tls/configs/client.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENTCCAx2gAwIBAgIUMu5h1ysA5DlM6lzZFliT2C2n4lEwDQYJKoZIhvcNAQEL +BQAwgaIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH +Ew1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKEwlIYXNoaUNvcnAxIzAhBgNVBAsTGlRl +c3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MS0wKwYDVQQDEyRQcm90b3R5cGUgVGVz +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwIBcNMjAwODA1MTg1MjAwWhgPMjEyMDA3 +MTIxODUyMDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzESMBAGA1UEChMJSGFzaGlDb3JwMSMwIQYD +VQQLExpUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOaGFzaGlj +b3JwLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/zYDKdDGo ++Qy7eJUNjOe6jpeGvK1lMu5T1Xka+h2ay6WH5gLyrPw5pi582iYpJdHVbplKMywx +LxZv7mAbKNxqdp8UZKy0A3bCuHQqRF8ssXXHufQ8EGxNkLMLJP0e2q39OnrxXekS +8Ct3aJm3V8qkcV3CpVdPNgJh4TSuneCXIxVWjFYSiyHi0/5TRd2D+aQPz12szg5F +mBW4dLzYKHEMlWcjWG8mxtbLyt+jSR1+tSehQx7KndufdfniOWEDBdbeR3yDnZdn +p8DnRWK4oaEI3Sl8tKlDd1Yp+R96aqOEn1tPW6Jy6Vdvk3fCefclbWZ6B9kiJ/1r +gxq7AN7iKmHNAgMBAAGjdTBzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr +BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRn2mwyk+MPChnLg0iWy1r9 +b3JvwTAfBgNVHSMEGDAWgBQAQ/zcb2C6aOc1TXg9Na/CCBWJQTANBgkqhkiG9w0B +AQsFAAOCAQEAOpCy0vHp1Kxgv0VBRrbrwSQLBGP8a1ubVWoeoZQ+EvX9ozqDrHxm +gM4XPYUJlUOOEu0ZRgCW60YK33E1zNKnA1F0/3/rmqMkKnm0BBs/5WzMWtsIBPcU +e0CeJmaRIXnERQMH/svD+RrFo1dcF8rUDIlWez7+xGqoIGBg7v4jEmkZ3HdckcE+ +/xvC61YSG8NsJwR/CEcQ8YCyVfgvuS0ukWs4dN15aVDL3Oe61h3bRcGAywOJBrdq +9xaq7ezZp/+lUSkYnatWJBuC/aviH9g9s+gMT0I3fWHh8BB0Ne2txwJ15K/qz5he +TjxFsumrh50aFqjSiEHndtY5UWuGAFLiSw== +-----END CERTIFICATE----- diff --git a/integrationTests/e2e-tls/configs/client.key b/integrationTests/e2e-tls/configs/client.key new file mode 100644 index 00000000..6c8fd05b --- /dev/null +++ b/integrationTests/e2e-tls/configs/client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAv82AynQxqPkMu3iVDYznuo6XhrytZTLuU9V5Gvodmsulh+YC +8qz8OaYufNomKSXR1W6ZSjMsMS8Wb+5gGyjcanafFGSstAN2wrh0KkRfLLF1x7n0 +PBBsTZCzCyT9Htqt/Tp68V3pEvArd2iZt1fKpHFdwqVXTzYCYeE0rp3glyMVVoxW +Eosh4tP+U0Xdg/mkD89drM4ORZgVuHS82ChxDJVnI1hvJsbWy8rfo0kdfrUnoUMe +yp3bn3X54jlhAwXW3kd8g52XZ6fA50ViuKGhCN0pfLSpQ3dWKfkfemqjhJ9bT1ui +culXb5N3wnn3JW1megfZIif9a4MauwDe4iphzQIDAQABAoIBAQCYHJuidAoaTwGZ +ACV9rJzuqD1lvubpFj5KwEcebPPjmtQ5deIqoaQa+D9wBvYyteq3ENKDNRg8HXL2 +7B7OC1bbHB5HZxxMW17pSK3gA39Ti52z+zbGF+Q8k6BbG0efG6DW7nUoTOkWeuCN +/6fA7uAoEDxirQwUJuo2xAsq3MyMLwcs95rke9Bly8ABFNaV1oMZq8YT/w8oSc2b +/7WtxXmChHlVYXTcMqzVPqNFqPRixZRWQ+BSHoXmEDviuGd51L4s9D7iXp32TvUx +DMHeS1DFA2en7ZF1uc9VXZeplkkDtVhUe4d6qOqCcUwDFEvMonnyVSa6/FkR5jYZ +2yujTdfhAoGBAM0hGOnmnDnCjADUt4mZlr+Mf0XmdKzEV+hid4CQUvBoTXgjYMvv +c397eNePce7SwSUE1/APERInGUPhRLVFW5q6/34WRtGBbQkT8ByeJANXes4UFZe3 +wdNLczWUlSl0G3jTf+Kh3+K5/PtmyxSrAS/9GIk+ibs1mlJOPyVnWqUJAoGBAO9e +WlP9/ruXluvkQyM5ZlnAnZYMsFGzzPx4tkazUjurtqxQoyZ0z+pPItGQ7lOl+pDA +EWiTun66g+Da9uBiBCJUeXiC1ge2p6bT6N194BrYyrWML9hcIL4mqVojUEUmhnSh +6b9h1pC7vFmw5ZFMIIkS60cfBMgQMZxMJN8NuaulAoGBAJM5hwURg90c2ZkbEyPK +PVz7fLlxnxoEzcc3LOf0LeLoKXnpgma8VJwRxXiJNs+fKgrkwAtG9QyfTU3f1412 +2zlhr1ASsv9ZMiXKzpHrmpNfbP+NgLXkqFN7mpPBMZGQCMuemPHTFrpGnODfNTB/ +T5newIZ4gSgBX+Jk0IOK+47pAoGAeKo6pK6ck9pV5TIbOg18b/AuQG7DD1yxD/CW +CkvpP1VPb8vygrdN/FLKPZRu39IC3qdD31DhKXNCeb5Hx1MBvICS/1INLLRCDVIz +yDvlFgOFJEG3+LxwcQqyQlMc6s8B5pecarKaZDmPODN5dmZG3HKiEicr1OJ878pe +p+aWW1UCgYBmGFbCc1qqlqp+srYGsv3rIgNs5HSfrAjbgY8xh9foMgrYCRAm57gv +01yVxMXWmKA6ReVEu8OTVy9fkuOL/vw2o+C6W4IPZYdvSQoPwd5Lf+AqxEQvFF1m +tT3SZAM3EhQ7tIXdIQHY27SJ1KlUJMrvUq1CiRWiG/MOKf/87JXPog== +-----END RSA PRIVATE KEY----- diff --git a/integrationTests/e2e-tls/configs/config.hcl b/integrationTests/e2e-tls/configs/config.hcl new file mode 100644 index 00000000..bf5f9f24 --- /dev/null +++ b/integrationTests/e2e-tls/configs/config.hcl @@ -0,0 +1,15 @@ +ui = false +disable_mlock = true + +listener "tcp" { + address = "[::]:8200" + cluster_address = "[::]:8201" + tls_cert_file = "/etc/vault/server.crt" + tls_key_file = "/etc/vault/server.key" + tls_client_ca_file = "/etc/vault/ca.crt" + tls_require_and_verify_client_cert = "true" +} + +storage "file" { + path = "/var/lib/vault" +} \ No newline at end of file diff --git a/integrationTests/e2e-tls/configs/server.crt b/integrationTests/e2e-tls/configs/server.crt new file mode 100644 index 00000000..4d9cb284 --- /dev/null +++ b/integrationTests/e2e-tls/configs/server.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIUAswquazrfsyDRvXZwn5718DUhU4wDQYJKoZIhvcNAQEL +BQAwgaIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH +Ew1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKEwlIYXNoaUNvcnAxIzAhBgNVBAsTGlRl +c3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MS0wKwYDVQQDEyRQcm90b3R5cGUgVGVz +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwIBcNMjAwODA1MTg1MjAwWhgPMjEyMDA3 +MTIxODUyMDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzESMBAGA1UEChMJSGFzaGlDb3JwMSMwIQYD +VQQLExpUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOaGFzaGlj +b3JwLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0azdZsrPC +5Rv8nRxVJnLi+oZgCJYgzhCDiEbYqt1QK1gqNXp0ml5ck6ycj0drwzHzrrX+xcPV +5FcNKH3RFyon9XkzjwaXkMv6IkgvH6/jQ1dDW9kWBf3Io3Y59wnD/YaIzNK0CYJS +fRNdsZb4InH8gh+RL33+FeysgJwXG1TVA4tTUj7DQxDE0cDd9UD+C9Yx7OWiUjC1 +IjqdFPusX1nziKYjeI5/UiCmOUGqJJRoMPonuzuGIj9GdmBKmga64OfeZFqn4f6a +ay61VnGCwZ24VniUwYElsFbcF2Nv9WqnrOeQlHOsYN68VMqHzaYPqE6SPa6mO5mI +/tmpXrDG3Y+RAgMBAAGjgZ0wgZowDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG +CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFE03/UTs2ZmJpWHSmstt +hDngW6F3MB8GA1UdIwQYMBaAFABD/NxvYLpo5zVNeD01r8IIFYlBMCUGA1UdEQQe +MByCCWxvY2FsaG9zdIIJdmF1bHQtdGxzhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IB +AQCzarBGJium5oZDSSP5GqxpS13QP2onEen6I1k2eRdcOqtbfNdQ20RJrb4dfNkE +Dc09KWVlZAn+hYge2KKTXJ+4ltIC9V1LvquyWipNczOT1ve0H9gt3Wm88LdESqI5 +HOx43pIaa3cWXBlbzrFmT1SASYm1V5Oo1mXzpUukGokHLLmAz36VVuJGbD0BxYke +5MefG4tNT1SsMsIqVvGxI9NiVs7YTdJu81MctSYK5snsEKnYdi9N7CHOk3bdDpeC +v2Vo7XBk3s4sBMGmnJO+1JOcRFJioooEFkqNyQmg3atfInysVbreKS5KtWNTaCPm +yI55plW8ga5ucja2VX3WbwAO +-----END CERTIFICATE----- diff --git a/integrationTests/e2e-tls/configs/server.key b/integrationTests/e2e-tls/configs/server.key new file mode 100644 index 00000000..8c81112e --- /dev/null +++ b/integrationTests/e2e-tls/configs/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAtGs3WbKzwuUb/J0cVSZy4vqGYAiWIM4Qg4hG2KrdUCtYKjV6 +dJpeXJOsnI9Ha8Mx8661/sXD1eRXDSh90RcqJ/V5M48Gl5DL+iJILx+v40NXQ1vZ +FgX9yKN2OfcJw/2GiMzStAmCUn0TXbGW+CJx/IIfkS99/hXsrICcFxtU1QOLU1I+ +w0MQxNHA3fVA/gvWMezlolIwtSI6nRT7rF9Z84imI3iOf1IgpjlBqiSUaDD6J7s7 +hiI/RnZgSpoGuuDn3mRap+H+mmsutVZxgsGduFZ4lMGBJbBW3Bdjb/Vqp6znkJRz +rGDevFTKh82mD6hOkj2upjuZiP7ZqV6wxt2PkQIDAQABAoIBAQCvK0HsVvLtkSCh +HbF6gwAcnHyHFQ8d/rRN4KxYhVynD85j/NRODer8G20F/J6tZDFFlSWinUTMkQxr +/BpcPg9yCIWKp50Q30cMLujCyBMvphw9jBmzplGG0h5hnRbgMXDDtYoFvw3HJST+ +XQRlGpxtO7GGdwPvBD5sJdpnHOQ6g7qIYKmlHM99kHU8vr0VghqZAYxEh8RpnYez +NLra+7ep+Zp1pFIniU6B8ohyL3OArbQ65qYrZYriAEI5HeEk0RhjewcPsV56LwbS +CncTVS/dNYgk1zRIvytmbDVD3v/4lLvnpIWeKVdk7p1aGJeCdpLeWNvDLX0Ws67r +QeZQizwhAoGBAMwAIA6+HPsx+8dhNbN3ydX8YU6uUfSeshhshIFZPIYL2vrKyAHU +/GAYVzYJH/cU0IvlLJlLdQuiZkOXEX87tgdfmM/o4Qdl12RR0BvU0Cae0txtzNrP +yTdfZqDhTz/V8jOAXUNA5oQA45Y3rI7JES8hBd1F9WFOH2WINp344GzlAoGBAOJo +SgmRE24VcnfUMqrBpwZBdBrTxDQyTagvd+MuGomIQfcE2Y4rr1eIuJJ0HF5/eYxc +DZRO/LVP9tQ8ozXi2tdmgUdKC79O2edmdOCWW5of464R/TLcM5B4SmS36RtdE3qJ +ig4fcUmsJ15MAGpkXLMh5YSD/N3TmcnURtx06Fk9AoGATi+mGcBnnybzFuF9EYHR +y7/lE6DgLF8+ZvoAdwralY2pqgFaUslsyO/LTRyGMc66d0OoqkAvZfwiMbmOrTMX +ew/6o4Tf6lPwD7UDjAcul/67VlyG7T5CIoTf8r0oAJFhOLf0BrizINiuYX6JFlid +y3BerQYJG/gzNFjWhglDCrkCgYA+3wUISRAjNrN10ShMwL/3/b8XIA1RDVMBTEU3 +gfr+jCb9SIx9bWYgoafXi4TBPRbswjdHIvQMCWuankgYU6m/vQhTWp2Of4AFQS9d +moNPdmGMWhR8xidPjAfklimWXq9lDMKYj2SvN64rAmHvKXWQjO4mcVyL4RHIuTkA +STqoZQKBgQDKHd8F6tjZHEFolmjS5l682g7zVTpBhozezJ/RqYvhJh5ew1pXoD/O +Zu9iMfHoDjR4ZUXq6aeLUj/oIt1AsjwaGChOLLAvFbvePgS9XkYkwIlaxS4efAya ++CQE/JmY/a1/c2MDLNMCEXvUqX68pv6iDF8pfn+i4tn0omYqgfUlCA== +-----END RSA PRIVATE KEY----- diff --git a/integrationTests/e2e-tls/e2e-tls.test.js b/integrationTests/e2e-tls/e2e-tls.test.js new file mode 100644 index 00000000..c04f918a --- /dev/null +++ b/integrationTests/e2e-tls/e2e-tls.test.js @@ -0,0 +1,13 @@ +describe('e2e-tls', () => { + it('verify', () => { + expect(process.env.SECRET).toBe("SUPERSECRET"); + expect(process.env.NAMED_SECRET).toBe("SUPERSECRET"); + expect(process.env.OTHERSECRET).toBe("OTHERSUPERSECRET"); + expect(process.env.OTHER_SECRET_OUTPUT).toBe("OTHERSUPERSECRET"); + expect(process.env.ALTSECRET).toBe("CUSTOMSECRET"); + expect(process.env.NAMED_ALTSECRET).toBe("CUSTOMSECRET"); + expect(process.env.OTHERALTSECRET).toBe("OTHERCUSTOMSECRET"); + expect(process.env.FOO).toBe("bar"); + expect(process.env.NAMED_CUBBYSECRET).toBe("zap"); + }); +}); diff --git a/integrationTests/e2e-tls/jest.config.js b/integrationTests/e2e-tls/jest.config.js new file mode 100644 index 00000000..03d15be8 --- /dev/null +++ b/integrationTests/e2e-tls/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + verbose: true +}; diff --git a/integrationTests/e2e-tls/setup.js b/integrationTests/e2e-tls/setup.js new file mode 100644 index 00000000..2314a33c --- /dev/null +++ b/integrationTests/e2e-tls/setup.js @@ -0,0 +1,180 @@ +const got = require('got'); +const core = require('@actions/core'); + +const vaultUrl = `${process.env.VAULT_HOST}:${process.env.VAULT_PORT}`; +const caCertificateRaw = `${process.env.VAULTCA}`; +const clientCertificateRaw = `${process.env.VAULT_CLIENT_CERT}`; +const clientKeyRaw = `${process.env.VAULT_CLIENT_KEY}`; + +(async () => { + try { + var caCertificate = Buffer.from(caCertificateRaw, 'base64').toString(); + if (caCertificate == null) { + throw Error("VAULTCA env not set.") + } + + var clientCertificate = Buffer.from(clientCertificateRaw, 'base64').toString(); + if (clientCertificate == null) { + throw Error("VAULT_CLIENT_CERT env not set.") + } + + var clientKey = Buffer.from(clientKeyRaw, 'base64').toString(); + if (clientKey == null) { + throw Error("VAULT_CLIENT_KEY env not set.") + } + + // Init + const {body} = await got(`https://${vaultUrl}/v1/sys/init`, { + method: 'POST', + json: { + secret_shares: 1, + secret_threshold: 1, + }, + responseType: 'json', + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + } + }); + + if (body.keys_base64.length != 1) { + throw Error("No unseal key found after init.") + } + var unseal = body.keys_base64[0]; + + if (body.root_token == "") { + throw Error("No root token found after init.") + } + var rootToken = body.root_token; + + core.exportVariable('VAULT_TOKEN', rootToken); + core.setSecret(rootToken) + + // Unseal + await got(`https://${vaultUrl}/v1/sys/unseal`, { + method: 'POST', + json: { + key: unseal, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + } + }); + + await got(`https://${vaultUrl}/v1/sys/mounts/secret`, { + method: 'POST', + headers: { + 'X-Vault-Token': rootToken, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + }, + json: { + type: 'kv-v2' + } + }); + + await got(`https://${vaultUrl}/v1/secret/data/test`, { + method: 'POST', + headers: { + 'X-Vault-Token': rootToken, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + }, + json: { + data: { + secret: 'SUPERSECRET', + }, + }, + }); + + await got(`https://${vaultUrl}/v1/secret/data/nested/test`, { + method: 'POST', + headers: { + 'X-Vault-Token': rootToken, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + }, + json: { + data: { + otherSecret: 'OTHERSUPERSECRET', + }, + } + }); + + await got(`https://${vaultUrl}/v1/sys/mounts/my-secret`, { + method: 'POST', + headers: { + 'X-Vault-Token': rootToken, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + }, + json: { + type: 'kv' + } + }); + + await got(`https://${vaultUrl}/v1/my-secret/test`, { + method: 'POST', + headers: { + 'X-Vault-Token': rootToken, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + }, + json: { + altSecret: 'CUSTOMSECRET', + } + }); + + await got(`https://${vaultUrl}/v1/my-secret/nested/test`, { + method: 'POST', + headers: { + 'X-Vault-Token': rootToken, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + }, + json: { + otherAltSecret: 'OTHERCUSTOMSECRET', + }, + }); + + await got(`https://${vaultUrl}/v1/cubbyhole/test`, { + method: 'POST', + headers: { + 'X-Vault-Token': rootToken, + }, + https: { + certificateAuthority: caCertificate, + certificate: clientCertificate, + key: clientKey, + }, + json: { + foo: 'bar', + zip: 'zap', + }, + }); + } catch (error) { + console.log(error); + process.exit(1); + } +})(); diff --git a/package-lock.json b/package-lock.json index 0774c2fd..7dbcf01a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1873,9 +1873,9 @@ } }, "@sindresorhus/is": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.0.tgz", - "integrity": "sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.0.tgz", + "integrity": "sha512-n4J+zu52VdY43kdi/XdI9DzuMr1Mur8zFL5ZRG2opCans9aiFwkPxHYFEb5Xgy7n1Z4K6WfI4FpqUqsh3E8BPQ==" }, "@sinonjs/commons": { "version": "1.7.1", @@ -2813,13 +2813,9 @@ } }, "cacheable-lookup": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", - "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", - "requires": { - "@types/keyv": "^3.1.1", - "keyv": "^4.0.0" - } + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz", + "integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w==" }, "cacheable-request": { "version": "7.0.1", @@ -2962,13 +2958,6 @@ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", "requires": { "mimic-response": "^1.0.0" - }, - "dependencies": { - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - } } }, "co": { @@ -3284,11 +3273,18 @@ "dev": true }, "decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "requires": { - "mimic-response": "^2.0.0" + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } } }, "deep-extend": { @@ -3433,11 +3429,6 @@ "readable-stream": "^2.0.2" } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -4120,40 +4111,21 @@ } }, "got": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", - "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/got/-/got-11.5.1.tgz", + "integrity": "sha512-reQEZcEBMTGnujmQ+Wm97mJs/OK6INtO6HmLI+xt3+9CvnRwWjXutUvb2mqr+Ao4Lu05Rx6+udx9sOQAmExMxA==", "requires": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", + "@sindresorhus/is": "^3.0.0", + "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.0", "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "requires": { - "pump": "^3.0.0" - } - }, - "type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" - } + "responselike": "^2.0.0" } }, "graceful-fs": { @@ -4310,6 +4282,22 @@ "sshpk": "^1.7.0" } }, + "http2-wrapper": { + "version": "1.0.0-beta.5.2", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz", + "integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "dependencies": { + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + } + } + }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -7647,9 +7635,9 @@ } }, "keyv": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.0.tgz", - "integrity": "sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.1.tgz", + "integrity": "sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw==", "requires": { "json-buffer": "3.0.1" } @@ -8054,9 +8042,9 @@ "dev": true }, "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "minimatch": { "version": "3.0.4", @@ -8305,9 +8293,9 @@ "dev": true }, "normalize-url": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.4.1.tgz", - "integrity": "sha512-rjH3yRt0Ssx19mUwS0hrDUOdG9VI+oRLpLHJ7tXRdjcuQ7v7wo6qPvOZppHRrqfslTKr0L2yBhjj4UXd7c3cQg==" + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" }, "npm": { "version": "6.14.4", @@ -11972,14 +11960,6 @@ "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", "dev": true }, - "p-event": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz", - "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==", - "requires": { - "p-timeout": "^2.0.1" - } - }, "p-filter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", @@ -11992,7 +11972,8 @@ "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true }, "p-is-promise": { "version": "3.0.0", @@ -12040,14 +12021,6 @@ "retry": "^0.12.0" } }, - "p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "requires": { - "p-finally": "^1.0.0" - } - }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -12550,6 +12523,11 @@ "path-parse": "^1.0.6" } }, + "resolve-alpn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz", + "integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==" + }, "resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -13550,11 +13528,6 @@ } } }, - "to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==" - }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", diff --git a/package.json b/package.json index 37a77e8b..83387bb7 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "test": "jest", "test:integration:basic": "jest -c integrationTests/basic/jest.config.js", "test:integration:enterprise": "jest -c integrationTests/enterprise/jest.config.js", - "test:e2e": "jest -c integrationTests/e2e/jest.config.js" + "test:e2e": "jest -c integrationTests/e2e/jest.config.js", + "test:e2e-tls": "jest -c integrationTests/e2e-tls/jest.config.js" }, "files": [ "src/**/*", @@ -43,7 +44,7 @@ }, "homepage": "https://github.com/hashicorp/vault-action#readme", "dependencies": { - "got": "^10.2.2", + "got": "^11.5.1", "jsonata": "^1.8.2" }, "peerDependencies": { diff --git a/src/action.js b/src/action.js index ab8e1a59..82de947d 100644 --- a/src/action.js +++ b/src/action.js @@ -29,7 +29,28 @@ async function exportSecrets() { const defaultOptions = { prefixUrl: vaultUrl, - headers: {} + headers: {}, + https: {} + } + + const tlsSkipVerify = core.getInput('tlsSkipVerify', { required: false }) != 'false'; + if (tlsSkipVerify == true) { + defaultOptions.https.rejectUnauthorized = true; + } + + const caCertificateRaw = core.getInput('caCertificate', { required: false }); + if (caCertificateRaw != null) { + defaultOptions.https.certificateAuthority = Buffer.from(caCertificateRaw, 'base64').toString(); + } + + const clientCertificateRaw = core.getInput('clientCertificate', { required: false }); + if (clientCertificateRaw != null) { + defaultOptions.https.certificate = Buffer.from(clientCertificateRaw, 'base64').toString(); + } + + const clientKeyRaw = core.getInput('clientKey', { required: false }); + if (clientKeyRaw != null) { + defaultOptions.https.key = Buffer.from(clientKeyRaw, 'base64').toString(); } for (const [headerName, headerValue] of extraHeaders) { @@ -200,4 +221,4 @@ module.exports = { parseSecretsInput, normalizeOutputKey, parseHeadersInput -}; \ No newline at end of file +}; diff --git a/src/entry.js b/src/entry.js index 44b0e047..b0778613 100644 --- a/src/entry.js +++ b/src/entry.js @@ -7,4 +7,4 @@ const { exportSecrets } = require('./action'); } catch (error) { core.setFailed(error.message); } -})(); \ No newline at end of file +})();