@verdaccio/proxy 9.0.0-next-9.7 → 9.0.0-next-9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/agent.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Agents } from 'got';
1
2
  import { AgentOptionsConf } from '@verdaccio/types';
2
3
  declare class CustomAgents {
3
4
  private url;
package/build/proxy.js CHANGED
@@ -7,8 +7,7 @@ let debug = require("debug");
7
7
  debug = require_runtime.__toESM(debug);
8
8
  let got = require("got");
9
9
  got = require_runtime.__toESM(got);
10
- let lodash = require("lodash");
11
- lodash = require_runtime.__toESM(lodash);
10
+ let lodash_es = require("lodash-es");
12
11
  let node_stream = require("node:stream");
13
12
  let node_url = require("node:url");
14
13
  let _verdaccio_core = require("@verdaccio/core");
@@ -22,7 +21,7 @@ var contentTypeAccept = `${_verdaccio_core.HEADERS.JSON};`;
22
21
  * Just a helper (`config[key] || default` doesn't work because of zeroes)
23
22
  */
24
23
  var setConfig = (config, key, def) => {
25
- return lodash.default.isNil(config[key]) === false ? config[key] : def;
24
+ return (0, lodash_es.isNil)(config[key]) === false ? config[key] : def;
26
25
  };
27
26
  /**
28
27
  * Implements Storage interface
@@ -101,13 +100,13 @@ var ProxyStorage = class {
101
100
  setAuthNext(headers) {
102
101
  const { auth } = this.config;
103
102
  if (typeof auth === "undefined" || typeof headers[_verdaccio_core.HEADERS.AUTHORIZATION] === "string") return headers;
104
- if (lodash.default.isObject(auth) === false && lodash.default.isObject(auth.token) === false) this._throwErrorAuth("Auth invalid");
103
+ if ((0, lodash_es.isObject)(auth) === false && (0, lodash_es.isObject)(auth.token) === false) this._throwErrorAuth("Auth invalid");
105
104
  let token;
106
105
  const tokenConf = auth;
107
- if (lodash.default.isNil(tokenConf.token) === false && lodash.default.isString(tokenConf.token)) {
106
+ if ((0, lodash_es.isNil)(tokenConf.token) === false && typeof tokenConf.token === "string") {
108
107
  debug$1("use token from config");
109
108
  token = tokenConf.token;
110
- } else if (lodash.default.isNil(tokenConf.token_env) === false) if (typeof tokenConf.token_env === "string") {
109
+ } else if ((0, lodash_es.isNil)(tokenConf.token_env) === false) if (typeof tokenConf.token_env === "string") {
111
110
  debug$1("use token from env %o", tokenConf.token_env);
112
111
  token = process.env[tokenConf.token_env];
113
112
  } else if (typeof tokenConf.token_env === "boolean" && tokenConf.token_env) {
@@ -178,7 +177,7 @@ var ProxyStorage = class {
178
177
  let headers = this.getHeaders(options?.headers);
179
178
  headers = this.addProxyHeaders(headers, options.remoteAddress);
180
179
  headers = this.applyUplinkHeaders(headers);
181
- if (lodash.default.isNil(options.etag) === false) {
180
+ if ((0, lodash_es.isNil)(options.etag) === false) {
182
181
  headers[_verdaccio_core.HEADERS.NONE_MATCH] = options.etag;
183
182
  headers[_verdaccio_core.HEADERS.ACCEPT] = contentTypeAccept;
184
183
  }
@@ -231,7 +230,7 @@ var ProxyStorage = class {
231
230
  method,
232
231
  url: uri
233
232
  },
234
- status: lodash.default.isNull(eventResponse) === false ? eventResponse.statusCode : "ERR"
233
+ status: eventResponse !== null ? eventResponse.statusCode : "ERR"
235
234
  }, "@{!status}, req: '@{request.method} @{request.url}' (streaming)");
236
235
  }).on("downloadProgress", (progress) => {
237
236
  if (progress.total) {
@@ -286,7 +285,7 @@ var ProxyStorage = class {
286
285
  let headers = this.getHeaders(options?.headers);
287
286
  headers = this.addProxyHeaders(headers, options.remoteAddress);
288
287
  headers = this.applyUplinkHeaders(headers);
289
- if (lodash.default.isNil(options.etag) === false) {
288
+ if ((0, lodash_es.isNil)(options.etag) === false) {
290
289
  headers[_verdaccio_core.HEADERS.NONE_MATCH] = options.etag;
291
290
  headers[_verdaccio_core.HEADERS.ACCEPT] = contentTypeAccept;
292
291
  }
@@ -380,8 +379,8 @@ var ProxyStorage = class {
380
379
  if ("no_proxy" in config) noProxyList = config.no_proxy;
381
380
  else if ("no_proxy" in mainconfig) noProxyList = mainconfig.no_proxy;
382
381
  if (hostname[0] !== ".") hostname = "." + hostname;
383
- if (lodash.default.isString(noProxyList) && noProxyList.length) noProxyList = noProxyList.split(",");
384
- if (lodash.default.isArray(noProxyList)) for (let i = 0; i < noProxyList.length; i++) {
382
+ if (typeof noProxyList === "string" && noProxyList.length) noProxyList = noProxyList.split(",");
383
+ if (Array.isArray(noProxyList)) for (let i = 0; i < noProxyList.length; i++) {
385
384
  let noProxyItem = noProxyList[i];
386
385
  if (noProxyItem[0] !== ".") noProxyItem = "." + noProxyItem;
387
386
  if (hostname.endsWith(noProxyItem)) {
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.js","names":[],"sources":["../src/proxy.ts"],"sourcesContent":["import JSONStream from 'JSONStream';\nimport buildDebug from 'debug';\nimport type { Agents, Delays, RequestError, RetryOptions, Headers as gotHeaders } from 'got';\nimport got, { Options } from 'got';\nimport _ from 'lodash';\nimport type Stream from 'node:stream';\nimport { PassThrough, Readable } from 'node:stream';\nimport { URL } from 'node:url';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n HEADERS,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n authUtils,\n constants,\n errorUtils,\n} from '@verdaccio/core';\nimport type { AgentOptionsConf, Config, Logger, Manifest, UpLinkConf } from '@verdaccio/types';\n\nimport CustomAgents from './agent';\nimport { parseInterval } from './proxy-utils';\n\nconst debug = buildDebug('verdaccio:proxy');\n\nconst encode = function (thing): string {\n return encodeURIComponent(thing).replace(/^%40/, '@');\n};\n\nconst jsonContentType = HEADERS.JSON;\nconst contentTypeAccept = `${jsonContentType};`;\n\n/**\n * Just a helper (`config[key] || default` doesn't work because of zeroes)\n */\nconst setConfig = (config: UpLinkConfLocal, key: string, def): string => {\n return _.isNil(config[key]) === false ? config[key] : def;\n};\n\nexport type UpLinkConfLocal = UpLinkConf & {\n no_proxy?: string;\n};\n\nexport interface ProxyList {\n [key: string]: IProxy;\n}\n\nexport type ProxySearchParams = {\n url: string;\n abort: AbortController;\n query?: searchUtils.SearchQuery;\n headers?: Headers;\n retry?: Partial<RetryOptions>;\n};\nexport interface IProxy {\n uplinkName: string;\n config: UpLinkConfLocal;\n failed_requests: number;\n userAgent: string;\n ca?: string | void;\n logger: Logger;\n server_id: string;\n url: URL;\n maxage: number;\n timeout: Delays;\n max_fails: number;\n fail_timeout: number;\n search(options: ProxySearchParams): Promise<Stream.Readable>;\n getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]>;\n fetchTarball(\n url: string,\n options: Partial<Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>>\n ): PassThrough;\n}\n\n// this type is need it by storage\nexport { Options as FetchOptions };\n\nexport interface ISyncUplinksOptions extends Options {\n uplinksLook?: boolean;\n etag?: string;\n remoteAddress?: string;\n}\n\n/**\n * Implements Storage interface\n * (same for storage.js, local-storage.js, up-storage.js)\n */\nclass ProxyStorage implements IProxy {\n public uplinkName: string;\n public config: UpLinkConfLocal;\n public failed_requests: number;\n public userAgent: string;\n public ca: string | void;\n public logger: Logger;\n public server_id: string;\n public url: URL;\n public maxage: number;\n public timeout: Delays;\n public max_fails: number;\n public fail_timeout: number;\n public agent_options: AgentOptionsConf;\n public proxy: string | undefined;\n private agent: Agents;\n // @ts-ignore\n public last_request_time: number | null;\n public strict_ssl: boolean;\n private retry: Partial<RetryOptions>;\n\n public constructor(\n uplinkName: string,\n config: UpLinkConfLocal,\n mainConfig: Config,\n logger: Logger,\n agent?: Agents\n ) {\n this.uplinkName = uplinkName;\n this.config = config;\n this.failed_requests = 0;\n this.userAgent = mainConfig.user_agent ?? 'hidden';\n this.ca = config.ca;\n this.logger = logger;\n this.server_id = mainConfig.server_id;\n this.agent_options = setConfig(this.config, 'agent_options', {\n keepAlive: true,\n maxSockets: 40,\n maxFreeSockets: 10,\n }) as AgentOptionsConf;\n this.url = new URL(this.config.url);\n const isHTTPS = this.url.protocol === 'https:';\n this._setupProxy(this.url.hostname, config, mainConfig, isHTTPS);\n this.agent = agent ?? this.getAgent();\n this.config.url = this.config.url.replace(/\\/$/, '');\n\n if (this.config.timeout && Number(this.config.timeout) >= 1000) {\n this.logger.warn(\n [\n 'Too big timeout value: ' + this.config.timeout,\n 'We changed time format to nginx-like one',\n '(see http://nginx.org/en/docs/syntax.html)',\n 'so please update your config accordingly',\n ].join('\\n')\n );\n }\n\n // a bunch of different configurable timers\n this.maxage = parseInterval(setConfig(this.config, 'maxage', '2m'));\n // https://github.com/sindresorhus/got/blob/main/documentation/6-timeout.md\n this.timeout = {\n request: parseInterval(setConfig(this.config, 'timeout', '30s')),\n };\n debug('set timeout %s', this.timeout);\n this.max_fails = Number(setConfig(this.config, 'max_fails', this.config.max_fails ?? 2));\n this.fail_timeout = parseInterval(setConfig(this.config, 'fail_timeout', '5m'));\n this.strict_ssl = Boolean(setConfig(this.config, 'strict_ssl', true));\n this.retry = { limit: this.max_fails ?? 2 };\n }\n\n private getAgent() {\n if (!this.agent) {\n // TODO: the config.ca (certificates) is not yet injected here\n const agentInstance = new CustomAgents(this.config.url, this.proxy, this.agent_options);\n return agentInstance.get();\n } else {\n return this.agent;\n }\n }\n\n public getHeaders(headers = {}): gotHeaders {\n const accept = HEADERS.ACCEPT;\n const acceptEncoding = HEADERS.ACCEPT_ENCODING;\n const userAgent = HEADERS.USER_AGENT;\n\n headers[accept] = headers[accept] || contentTypeAccept;\n headers[acceptEncoding] = headers[acceptEncoding] || 'gzip';\n // registry.npmjs.org will only return search result if user-agent include string 'npm'\n headers[userAgent] = headers[userAgent] || `npm (${this.userAgent})`;\n return this.setAuthNext(headers);\n }\n\n /**\n * Validate configuration auth and assign Header authorization\n * @param {Object} headers\n * @return {Object}\n * @private\n */\n private setAuthNext(headers: gotHeaders): gotHeaders {\n const { auth } = this.config;\n if (typeof auth === 'undefined' || typeof headers[HEADERS.AUTHORIZATION] === 'string') {\n return headers;\n }\n\n if (_.isObject(auth) === false && _.isObject((auth as any).token) === false) {\n this._throwErrorAuth('Auth invalid');\n }\n\n // get NPM_TOKEN http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules\n // or get other variable export in env\n // https://github.com/verdaccio/verdaccio/releases/tag/v2.5.0\n let token: any;\n const tokenConf: any = auth;\n if (_.isNil(tokenConf.token) === false && _.isString(tokenConf.token)) {\n debug('use token from config');\n token = tokenConf.token;\n } else if (_.isNil(tokenConf.token_env) === false) {\n if (typeof tokenConf.token_env === 'string') {\n debug('use token from env %o', tokenConf.token_env);\n token = process.env[tokenConf.token_env];\n } else if (typeof tokenConf.token_env === 'boolean' && tokenConf.token_env) {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n } else {\n this.logger.error(constants.ERROR_CODE.token_required);\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n } else {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n }\n\n if (typeof token === 'undefined') {\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n\n // define type Auth allow basic and bearer\n const type = tokenConf.type || TOKEN_BASIC;\n debug('token type %o', type);\n this._setHeaderAuthorization(headers, type, token);\n\n return headers;\n }\n\n /**\n * @param {string} message\n * @throws {Error}\n * @private\n */\n private _throwErrorAuth(message: string): Error {\n this.logger.error(message);\n throw new Error(message);\n }\n\n /**\n * Assign Header authorization with type authentication\n * @param {Object} headers\n * @param {string} type\n * @param {string} token\n * @private\n */\n private _setHeaderAuthorization(headers: any, type: string, token: any): void {\n const _type: string = type.toLowerCase();\n\n if (_type !== TOKEN_BEARER.toLowerCase() && _type !== TOKEN_BASIC.toLowerCase()) {\n this._throwErrorAuth(`Auth type '${_type}' not allowed`);\n }\n\n headers[HEADERS.AUTHORIZATION] = authUtils.buildToken(type, token);\n }\n\n /**\n * It will add or override specified headers from config file.\n *\n * Eg:\n *\n * uplinks:\n npmjs:\n url: https://registry.npmjs.org/\n headers:\n Accept: \"application/vnd.npm.install-v2+json; q=1.0\"\n verdaccio-staging:\n url: https://mycompany.com/npm\n headers:\n Accept: \"application/json\"\n authorization: \"Basic YourBase64EncodedCredentials==\"\n\n * @param {Object} headers\n * @private\n */\n private applyUplinkHeaders(headers: gotHeaders): gotHeaders {\n if (!this.config.headers) {\n return headers;\n }\n\n // add/override headers specified in the config\n /* eslint guard-for-in: 0 */\n for (const key in this.config.headers) {\n headers[key] = this.config.headers[key];\n }\n return headers;\n }\n\n public async getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]> {\n if (this._ifRequestFailure()) {\n throw errorUtils.getInternalError(API_ERROR.UPLINK_OFFLINE);\n }\n\n // FUTURE: allow mix headers that comes from the client\n debug('getting metadata for package %s', name);\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (_.isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = options.method || 'GET';\n const uri = this.config.url + `/${encode(name)}`;\n debug('set retry limit is %s', this.retry.limit);\n let response;\n let responseLength = 0;\n try {\n const retry = options?.retry ?? this.retry;\n debug('retry initial count %s', retry);\n response = await got(uri, {\n headers,\n responseType: 'json',\n method,\n agent: this.agent,\n retry,\n timeout: this.timeout,\n hooks: {\n afterResponse: [\n (afterResponse) => {\n const code = afterResponse.statusCode;\n debug('after response code is %s', code);\n if (code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES) {\n if (this.failed_requests >= this.max_fails) {\n this.failed_requests = 0;\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now online'\n );\n }\n }\n\n return afterResponse;\n },\n ],\n beforeRetry: [\n (error: RequestError, count: number) => {\n debug('retry %s count: %s', uri, count);\n this.failed_requests = count ?? 0;\n this.logger.info(\n {\n request: {\n method: method,\n url: uri,\n },\n error: error.message,\n retryCount: this.failed_requests,\n },\n \"retry @{retryCount} req: '@{request.method} @{request.url}'\"\n );\n if (this.failed_requests >= this.max_fails) {\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now offline'\n );\n }\n },\n ],\n },\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n })\n .on<any>('response', (eventResponse) => {\n const message = \"@{!status}, req: '@{request.method} @{request.url}' (streaming)\";\n this.logger.http(\n {\n request: {\n method: method,\n url: uri,\n },\n status: _.isNull(eventResponse) === false ? eventResponse.statusCode : 'ERR',\n },\n message\n );\n })\n .on('downloadProgress', (progress) => {\n if (progress.total) {\n debug('responseLength %s', progress.total);\n responseLength = progress.total;\n }\n });\n const etag = response.headers.etag as string;\n const data = response.body;\n\n // not modified status (304) registry does not return any payload\n // it is handled as an error with the original 304 status preserved\n if (response?.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n const err = errorUtils.getNotFound(API_ERROR.NOT_MODIFIED_NO_DATA);\n err.code = HTTP_STATUS.NOT_MODIFIED;\n throw err;\n }\n\n debug('uri %s success', uri);\n const message = \"@{!status}, req: '@{request.method} @{request.url}'\";\n this.logger.http(\n {\n // if error is null/false change this to undefined so it wont log\n request: { method: method, url: uri },\n status: response.statusCode,\n bytes: {\n in: options?.json ? JSON.stringify(options?.json).length : 0,\n out: responseLength || 0,\n },\n },\n message\n );\n return [data, etag];\n } catch (err: any) {\n debug('error %s on uri %s', err.code, uri);\n if (err.code === 'ERR_NON_2XX_3XX_RESPONSE') {\n const code = err.response.statusCode;\n debug('error code %s', code);\n if (code === HTTP_STATUS.NOT_FOUND) {\n throw errorUtils.getNotFound(API_ERROR.NOT_PACKAGE_UPLINK);\n }\n\n if (!(code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES)) {\n const error = errorUtils.getInternalError(`${API_ERROR.BAD_STATUS_CODE}: ${code}`);\n // we need this code to identify outside which status code triggered the error\n error.remoteStatus = code;\n throw error;\n }\n } else if (this._isRequestTimeout(err)) {\n debug('error code timeout');\n throw errorUtils.getServiceUnavailable(API_ERROR.SERVER_TIME_OUT);\n }\n throw err;\n }\n }\n\n // FIXME: handle stream and retry\n public fetchTarball(\n url: string,\n overrideOptions: Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>\n ): any {\n debug('fetching url for %s', url);\n const options = { ...this.config, ...overrideOptions };\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (_.isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = 'GET';\n // const uri = this.config.url + `/${encode(name)}`;\n debug('request uri for %s', url);\n\n const readStream = got\n .stream(url, {\n headers,\n method,\n agent: this.agent,\n // FIXME: this should be taken from construtor as priority\n retry: this.retry ?? options?.retry,\n timeout: this.timeout,\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n });\n\n return readStream;\n }\n\n /**\n * Perform a stream search.\n * @param {*} options request options\n * @return {Stream}\n */\n public async search({ url, abort, retry }: ProxySearchParams): Promise<Stream.Readable> {\n try {\n // Incoming URL is relative ie /-/v1/search...\n const uri = new URL(url, this.url).href;\n this.logger.http(\n { uri, uplink: this.uplinkName },\n 'search request to uplink @{uplink} - @{uri}'\n );\n debug('searching on %o', uri);\n const response = got(uri, {\n signal: abort ? abort.signal : {},\n agent: this.agent,\n timeout: this.timeout,\n retry: retry ?? this.retry,\n });\n\n const res = await response.text();\n const total = JSON.parse(res).total;\n debug('number of packages found: %o', total);\n const streamSearch = new PassThrough({ objectMode: true });\n const streamResponse = Readable.from(res);\n // objects is one of the properties on the body, it ignores date and total\n streamResponse.pipe(JSONStream.parse('objects')).pipe(streamSearch, { end: true });\n return streamSearch;\n } catch (err: any) {\n debug('search error %s', err);\n if (err.response.statusCode === 409) {\n throw errorUtils.getInternalError(`bad status code ${err.response.statusCode} from uplink`);\n }\n this.logger.error(\n { errorMessage: err?.message, name: this.uplinkName },\n 'proxy uplink @{name} search error: @{errorMessage}'\n );\n throw err;\n }\n }\n\n private addProxyHeaders(headers: gotHeaders, remoteAddress?: string): gotHeaders {\n // Only submit X-Forwarded-For field if we don't have a proxy selected\n // in the config file.\n //\n // Otherwise misconfigured proxy could return 407\n if (!this.proxy) {\n headers[HEADERS.FORWARDED_FOR] =\n (headers['x-forwarded-for'] ? headers['x-forwarded-for'] + ', ' : '') + remoteAddress;\n }\n\n // always attach Via header to avoid loops, even if we're not proxying\n headers['via'] = headers['via'] ? headers['via'] + ', ' : '';\n headers['via'] += '1.1 ' + this.server_id + ' (Verdaccio)';\n\n return headers;\n }\n\n /**\n * If the request failure.\n * @return {boolean}\n * @private\n */\n private _ifRequestFailure(): boolean {\n return (\n this.failed_requests >= this.max_fails &&\n Math.abs(Date.now() - (this.last_request_time as number)) < this.fail_timeout\n );\n }\n\n /**\n * Check if the request timed out (network or http errors).\n * @param {RequestError} err\n * @return {boolean}\n */\n private _isRequestTimeout(err: RequestError): boolean {\n const code = err?.response?.statusCode;\n return (\n err.code === 'ETIMEDOUT' ||\n err.code === 'ESOCKETTIMEDOUT' ||\n err.code === 'ECONNRESET' ||\n code === HTTP_STATUS.REQUEST_TIMEOUT ||\n code === HTTP_STATUS.BAD_GATEWAY ||\n code === HTTP_STATUS.SERVICE_UNAVAILABLE ||\n code === HTTP_STATUS.GATEWAY_TIMEOUT\n );\n }\n\n /**\n * Set up a proxy.\n * @param {*} hostname\n * @param {*} config\n * @param {*} mainconfig\n * @param {*} isHTTPS\n */\n private _setupProxy(\n hostname: string,\n config: UpLinkConfLocal,\n mainconfig: Config,\n isHTTPS: boolean\n ): void {\n let noProxyList;\n const proxy_key: string = isHTTPS ? 'https_proxy' : 'http_proxy';\n debug('looking for %o', proxy_key);\n\n // get http_proxy and no_proxy configs\n if (proxy_key in config) {\n this.proxy = config[proxy_key];\n debug('found %o in uplink config', this.proxy);\n } else if (proxy_key in mainconfig) {\n this.proxy = mainconfig[proxy_key];\n debug('found %o in main config', this.proxy);\n }\n if ('no_proxy' in config) {\n noProxyList = config.no_proxy;\n } else if ('no_proxy' in mainconfig) {\n noProxyList = mainconfig.no_proxy;\n }\n\n // use wget-like algorithm to determine if proxy shouldn't be used\n if (hostname[0] !== '.') {\n hostname = '.' + hostname;\n }\n\n if (_.isString(noProxyList) && noProxyList.length) {\n noProxyList = noProxyList.split(',');\n }\n\n if (_.isArray(noProxyList)) {\n for (let i = 0; i < noProxyList.length; i++) {\n let noProxyItem = noProxyList[i];\n if (noProxyItem[0] !== '.') {\n noProxyItem = '.' + noProxyItem;\n }\n if (hostname.endsWith(noProxyItem)) {\n if (this.proxy) {\n debug('not using proxy, excluded by @{rule}', noProxyItem);\n this.logger.debug(\n { url: this.url.href, rule: noProxyItem },\n 'not using proxy for @{url}, excluded by @{rule} rule'\n );\n this.proxy = undefined;\n }\n break;\n }\n }\n }\n\n if (typeof this.proxy === 'string') {\n debug('using proxy @{proxy} for @{url}', this.proxy, this.url.href);\n this.logger.debug(\n { url: this.url.href, proxy: this.proxy },\n 'using proxy @{proxy} for @{url}'\n );\n }\n }\n}\n\nexport { ProxyStorage };\n"],"mappings":"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"}
1
+ {"version":3,"file":"proxy.js","names":[],"sources":["../src/proxy.ts"],"sourcesContent":["import JSONStream from 'JSONStream';\nimport buildDebug from 'debug';\nimport type { Agents, Delays, RequestError, RetryOptions, Headers as gotHeaders } from 'got';\nimport got, { Options } from 'got';\nimport { isNil, isObject } from 'lodash-es';\nimport type Stream from 'node:stream';\nimport { PassThrough, Readable } from 'node:stream';\nimport { URL } from 'node:url';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n HEADERS,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n authUtils,\n constants,\n errorUtils,\n} from '@verdaccio/core';\nimport type { AgentOptionsConf, Config, Logger, Manifest, UpLinkConf } from '@verdaccio/types';\n\nimport CustomAgents from './agent';\nimport { parseInterval } from './proxy-utils';\n\nconst debug = buildDebug('verdaccio:proxy');\n\nconst encode = function (thing): string {\n return encodeURIComponent(thing).replace(/^%40/, '@');\n};\n\nconst jsonContentType = HEADERS.JSON;\nconst contentTypeAccept = `${jsonContentType};`;\n\n/**\n * Just a helper (`config[key] || default` doesn't work because of zeroes)\n */\nconst setConfig = (config: UpLinkConfLocal, key: string, def): string => {\n return isNil(config[key]) === false ? config[key] : def;\n};\n\nexport type UpLinkConfLocal = UpLinkConf & {\n no_proxy?: string;\n};\n\nexport interface ProxyList {\n [key: string]: IProxy;\n}\n\nexport type ProxySearchParams = {\n url: string;\n abort: AbortController;\n query?: searchUtils.SearchQuery;\n headers?: Headers;\n retry?: Partial<RetryOptions>;\n};\nexport interface IProxy {\n uplinkName: string;\n config: UpLinkConfLocal;\n failed_requests: number;\n userAgent: string;\n ca?: string | void;\n logger: Logger;\n server_id: string;\n url: URL;\n maxage: number;\n timeout: Delays;\n max_fails: number;\n fail_timeout: number;\n search(options: ProxySearchParams): Promise<Stream.Readable>;\n getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]>;\n fetchTarball(\n url: string,\n options: Partial<Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>>\n ): PassThrough;\n}\n\n// this type is need it by storage\nexport { Options as FetchOptions };\n\nexport interface ISyncUplinksOptions extends Options {\n uplinksLook?: boolean;\n etag?: string;\n remoteAddress?: string;\n}\n\n/**\n * Implements Storage interface\n * (same for storage.js, local-storage.js, up-storage.js)\n */\nclass ProxyStorage implements IProxy {\n public uplinkName: string;\n public config: UpLinkConfLocal;\n public failed_requests: number;\n public userAgent: string;\n public ca: string | void;\n public logger: Logger;\n public server_id: string;\n public url: URL;\n public maxage: number;\n public timeout: Delays;\n public max_fails: number;\n public fail_timeout: number;\n public agent_options: AgentOptionsConf;\n public proxy: string | undefined;\n private agent: Agents;\n // @ts-ignore\n public last_request_time: number | null;\n public strict_ssl: boolean;\n private retry: Partial<RetryOptions>;\n\n public constructor(\n uplinkName: string,\n config: UpLinkConfLocal,\n mainConfig: Config,\n logger: Logger,\n agent?: Agents\n ) {\n this.uplinkName = uplinkName;\n this.config = config;\n this.failed_requests = 0;\n this.userAgent = mainConfig.user_agent ?? 'hidden';\n this.ca = config.ca;\n this.logger = logger;\n this.server_id = mainConfig.server_id;\n this.agent_options = setConfig(this.config, 'agent_options', {\n keepAlive: true,\n maxSockets: 40,\n maxFreeSockets: 10,\n }) as AgentOptionsConf;\n this.url = new URL(this.config.url);\n const isHTTPS = this.url.protocol === 'https:';\n this._setupProxy(this.url.hostname, config, mainConfig, isHTTPS);\n this.agent = agent ?? this.getAgent();\n this.config.url = this.config.url.replace(/\\/$/, '');\n\n if (this.config.timeout && Number(this.config.timeout) >= 1000) {\n this.logger.warn(\n [\n 'Too big timeout value: ' + this.config.timeout,\n 'We changed time format to nginx-like one',\n '(see http://nginx.org/en/docs/syntax.html)',\n 'so please update your config accordingly',\n ].join('\\n')\n );\n }\n\n // a bunch of different configurable timers\n this.maxage = parseInterval(setConfig(this.config, 'maxage', '2m'));\n // https://github.com/sindresorhus/got/blob/main/documentation/6-timeout.md\n this.timeout = {\n request: parseInterval(setConfig(this.config, 'timeout', '30s')),\n };\n debug('set timeout %s', this.timeout);\n this.max_fails = Number(setConfig(this.config, 'max_fails', this.config.max_fails ?? 2));\n this.fail_timeout = parseInterval(setConfig(this.config, 'fail_timeout', '5m'));\n this.strict_ssl = Boolean(setConfig(this.config, 'strict_ssl', true));\n this.retry = { limit: this.max_fails ?? 2 };\n }\n\n private getAgent() {\n if (!this.agent) {\n // TODO: the config.ca (certificates) is not yet injected here\n const agentInstance = new CustomAgents(this.config.url, this.proxy, this.agent_options);\n return agentInstance.get();\n } else {\n return this.agent;\n }\n }\n\n public getHeaders(headers = {}): gotHeaders {\n const accept = HEADERS.ACCEPT;\n const acceptEncoding = HEADERS.ACCEPT_ENCODING;\n const userAgent = HEADERS.USER_AGENT;\n\n headers[accept] = headers[accept] || contentTypeAccept;\n headers[acceptEncoding] = headers[acceptEncoding] || 'gzip';\n // registry.npmjs.org will only return search result if user-agent include string 'npm'\n headers[userAgent] = headers[userAgent] || `npm (${this.userAgent})`;\n return this.setAuthNext(headers);\n }\n\n /**\n * Validate configuration auth and assign Header authorization\n * @param {Object} headers\n * @return {Object}\n * @private\n */\n private setAuthNext(headers: gotHeaders): gotHeaders {\n const { auth } = this.config;\n if (typeof auth === 'undefined' || typeof headers[HEADERS.AUTHORIZATION] === 'string') {\n return headers;\n }\n\n if (isObject(auth) === false && isObject((auth as any).token) === false) {\n this._throwErrorAuth('Auth invalid');\n }\n\n // get NPM_TOKEN http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules\n // or get other variable export in env\n // https://github.com/verdaccio/verdaccio/releases/tag/v2.5.0\n let token: any;\n const tokenConf: any = auth;\n if (isNil(tokenConf.token) === false && typeof tokenConf.token === 'string') {\n debug('use token from config');\n token = tokenConf.token;\n } else if (isNil(tokenConf.token_env) === false) {\n if (typeof tokenConf.token_env === 'string') {\n debug('use token from env %o', tokenConf.token_env);\n token = process.env[tokenConf.token_env];\n } else if (typeof tokenConf.token_env === 'boolean' && tokenConf.token_env) {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n } else {\n this.logger.error(constants.ERROR_CODE.token_required);\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n } else {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n }\n\n if (typeof token === 'undefined') {\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n\n // define type Auth allow basic and bearer\n const type = tokenConf.type || TOKEN_BASIC;\n debug('token type %o', type);\n this._setHeaderAuthorization(headers, type, token);\n\n return headers;\n }\n\n /**\n * @param {string} message\n * @throws {Error}\n * @private\n */\n private _throwErrorAuth(message: string): Error {\n this.logger.error(message);\n throw new Error(message);\n }\n\n /**\n * Assign Header authorization with type authentication\n * @param {Object} headers\n * @param {string} type\n * @param {string} token\n * @private\n */\n private _setHeaderAuthorization(headers: any, type: string, token: any): void {\n const _type: string = type.toLowerCase();\n\n if (_type !== TOKEN_BEARER.toLowerCase() && _type !== TOKEN_BASIC.toLowerCase()) {\n this._throwErrorAuth(`Auth type '${_type}' not allowed`);\n }\n\n headers[HEADERS.AUTHORIZATION] = authUtils.buildToken(type, token);\n }\n\n /**\n * It will add or override specified headers from config file.\n *\n * Eg:\n *\n * uplinks:\n npmjs:\n url: https://registry.npmjs.org/\n headers:\n Accept: \"application/vnd.npm.install-v2+json; q=1.0\"\n verdaccio-staging:\n url: https://mycompany.com/npm\n headers:\n Accept: \"application/json\"\n authorization: \"Basic YourBase64EncodedCredentials==\"\n\n * @param {Object} headers\n * @private\n */\n private applyUplinkHeaders(headers: gotHeaders): gotHeaders {\n if (!this.config.headers) {\n return headers;\n }\n\n // add/override headers specified in the config\n /* eslint guard-for-in: 0 */\n for (const key in this.config.headers) {\n headers[key] = this.config.headers[key];\n }\n return headers;\n }\n\n public async getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]> {\n if (this._ifRequestFailure()) {\n throw errorUtils.getInternalError(API_ERROR.UPLINK_OFFLINE);\n }\n\n // FUTURE: allow mix headers that comes from the client\n debug('getting metadata for package %s', name);\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = options.method || 'GET';\n const uri = this.config.url + `/${encode(name)}`;\n debug('set retry limit is %s', this.retry.limit);\n let response;\n let responseLength = 0;\n try {\n const retry = options?.retry ?? this.retry;\n debug('retry initial count %s', retry);\n response = await got(uri, {\n headers,\n responseType: 'json',\n method,\n agent: this.agent,\n retry,\n timeout: this.timeout,\n hooks: {\n afterResponse: [\n (afterResponse) => {\n const code = afterResponse.statusCode;\n debug('after response code is %s', code);\n if (code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES) {\n if (this.failed_requests >= this.max_fails) {\n this.failed_requests = 0;\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now online'\n );\n }\n }\n\n return afterResponse;\n },\n ],\n beforeRetry: [\n (error: RequestError, count: number) => {\n debug('retry %s count: %s', uri, count);\n this.failed_requests = count ?? 0;\n this.logger.info(\n {\n request: {\n method: method,\n url: uri,\n },\n error: error.message,\n retryCount: this.failed_requests,\n },\n \"retry @{retryCount} req: '@{request.method} @{request.url}'\"\n );\n if (this.failed_requests >= this.max_fails) {\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now offline'\n );\n }\n },\n ],\n },\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n })\n .on<any>('response', (eventResponse) => {\n const message = \"@{!status}, req: '@{request.method} @{request.url}' (streaming)\";\n this.logger.http(\n {\n request: {\n method: method,\n url: uri,\n },\n status: eventResponse !== null ? eventResponse.statusCode : 'ERR',\n },\n message\n );\n })\n .on('downloadProgress', (progress) => {\n if (progress.total) {\n debug('responseLength %s', progress.total);\n responseLength = progress.total;\n }\n });\n const etag = response.headers.etag as string;\n const data = response.body;\n\n // not modified status (304) registry does not return any payload\n // it is handled as an error with the original 304 status preserved\n if (response?.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n const err = errorUtils.getNotFound(API_ERROR.NOT_MODIFIED_NO_DATA);\n err.code = HTTP_STATUS.NOT_MODIFIED;\n throw err;\n }\n\n debug('uri %s success', uri);\n const message = \"@{!status}, req: '@{request.method} @{request.url}'\";\n this.logger.http(\n {\n // if error is null/false change this to undefined so it wont log\n request: { method: method, url: uri },\n status: response.statusCode,\n bytes: {\n in: options?.json ? JSON.stringify(options?.json).length : 0,\n out: responseLength || 0,\n },\n },\n message\n );\n return [data, etag];\n } catch (err: any) {\n debug('error %s on uri %s', err.code, uri);\n if (err.code === 'ERR_NON_2XX_3XX_RESPONSE') {\n const code = err.response.statusCode;\n debug('error code %s', code);\n if (code === HTTP_STATUS.NOT_FOUND) {\n throw errorUtils.getNotFound(API_ERROR.NOT_PACKAGE_UPLINK);\n }\n\n if (!(code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES)) {\n const error = errorUtils.getInternalError(`${API_ERROR.BAD_STATUS_CODE}: ${code}`);\n // we need this code to identify outside which status code triggered the error\n error.remoteStatus = code;\n throw error;\n }\n } else if (this._isRequestTimeout(err)) {\n debug('error code timeout');\n throw errorUtils.getServiceUnavailable(API_ERROR.SERVER_TIME_OUT);\n }\n throw err;\n }\n }\n\n // FIXME: handle stream and retry\n public fetchTarball(\n url: string,\n overrideOptions: Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>\n ): any {\n debug('fetching url for %s', url);\n const options = { ...this.config, ...overrideOptions };\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = 'GET';\n // const uri = this.config.url + `/${encode(name)}`;\n debug('request uri for %s', url);\n\n const readStream = got\n .stream(url, {\n headers,\n method,\n agent: this.agent,\n // FIXME: this should be taken from construtor as priority\n retry: this.retry ?? options?.retry,\n timeout: this.timeout,\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n });\n\n return readStream;\n }\n\n /**\n * Perform a stream search.\n * @param {*} options request options\n * @return {Stream}\n */\n public async search({ url, abort, retry }: ProxySearchParams): Promise<Stream.Readable> {\n try {\n // Incoming URL is relative ie /-/v1/search...\n const uri = new URL(url, this.url).href;\n this.logger.http(\n { uri, uplink: this.uplinkName },\n 'search request to uplink @{uplink} - @{uri}'\n );\n debug('searching on %o', uri);\n const response = got(uri, {\n signal: abort ? abort.signal : {},\n agent: this.agent,\n timeout: this.timeout,\n retry: retry ?? this.retry,\n });\n\n const res = await response.text();\n const total = JSON.parse(res).total;\n debug('number of packages found: %o', total);\n const streamSearch = new PassThrough({ objectMode: true });\n const streamResponse = Readable.from(res);\n // objects is one of the properties on the body, it ignores date and total\n streamResponse.pipe(JSONStream.parse('objects')).pipe(streamSearch, { end: true });\n return streamSearch;\n } catch (err: any) {\n debug('search error %s', err);\n if (err.response.statusCode === 409) {\n throw errorUtils.getInternalError(`bad status code ${err.response.statusCode} from uplink`);\n }\n this.logger.error(\n { errorMessage: err?.message, name: this.uplinkName },\n 'proxy uplink @{name} search error: @{errorMessage}'\n );\n throw err;\n }\n }\n\n private addProxyHeaders(headers: gotHeaders, remoteAddress?: string): gotHeaders {\n // Only submit X-Forwarded-For field if we don't have a proxy selected\n // in the config file.\n //\n // Otherwise misconfigured proxy could return 407\n if (!this.proxy) {\n headers[HEADERS.FORWARDED_FOR] =\n (headers['x-forwarded-for'] ? headers['x-forwarded-for'] + ', ' : '') + remoteAddress;\n }\n\n // always attach Via header to avoid loops, even if we're not proxying\n headers['via'] = headers['via'] ? headers['via'] + ', ' : '';\n headers['via'] += '1.1 ' + this.server_id + ' (Verdaccio)';\n\n return headers;\n }\n\n /**\n * If the request failure.\n * @return {boolean}\n * @private\n */\n private _ifRequestFailure(): boolean {\n return (\n this.failed_requests >= this.max_fails &&\n Math.abs(Date.now() - (this.last_request_time as number)) < this.fail_timeout\n );\n }\n\n /**\n * Check if the request timed out (network or http errors).\n * @param {RequestError} err\n * @return {boolean}\n */\n private _isRequestTimeout(err: RequestError): boolean {\n const code = err?.response?.statusCode;\n return (\n err.code === 'ETIMEDOUT' ||\n err.code === 'ESOCKETTIMEDOUT' ||\n err.code === 'ECONNRESET' ||\n code === HTTP_STATUS.REQUEST_TIMEOUT ||\n code === HTTP_STATUS.BAD_GATEWAY ||\n code === HTTP_STATUS.SERVICE_UNAVAILABLE ||\n code === HTTP_STATUS.GATEWAY_TIMEOUT\n );\n }\n\n /**\n * Set up a proxy.\n * @param {*} hostname\n * @param {*} config\n * @param {*} mainconfig\n * @param {*} isHTTPS\n */\n private _setupProxy(\n hostname: string,\n config: UpLinkConfLocal,\n mainconfig: Config,\n isHTTPS: boolean\n ): void {\n let noProxyList;\n const proxy_key: string = isHTTPS ? 'https_proxy' : 'http_proxy';\n debug('looking for %o', proxy_key);\n\n // get http_proxy and no_proxy configs\n if (proxy_key in config) {\n this.proxy = config[proxy_key];\n debug('found %o in uplink config', this.proxy);\n } else if (proxy_key in mainconfig) {\n this.proxy = mainconfig[proxy_key];\n debug('found %o in main config', this.proxy);\n }\n if ('no_proxy' in config) {\n noProxyList = config.no_proxy;\n } else if ('no_proxy' in mainconfig) {\n noProxyList = mainconfig.no_proxy;\n }\n\n // use wget-like algorithm to determine if proxy shouldn't be used\n if (hostname[0] !== '.') {\n hostname = '.' + hostname;\n }\n\n if (typeof noProxyList === 'string' && noProxyList.length) {\n noProxyList = noProxyList.split(',');\n }\n\n if (Array.isArray(noProxyList)) {\n for (let i = 0; i < noProxyList.length; i++) {\n let noProxyItem = noProxyList[i];\n if (noProxyItem[0] !== '.') {\n noProxyItem = '.' + noProxyItem;\n }\n if (hostname.endsWith(noProxyItem)) {\n if (this.proxy) {\n debug('not using proxy, excluded by @{rule}', noProxyItem);\n this.logger.debug(\n { url: this.url.href, rule: noProxyItem },\n 'not using proxy for @{url}, excluded by @{rule} rule'\n );\n this.proxy = undefined;\n }\n break;\n }\n }\n }\n\n if (typeof this.proxy === 'string') {\n debug('using proxy @{proxy} for @{url}', this.proxy, this.url.href);\n this.logger.debug(\n { url: this.url.href, proxy: this.proxy },\n 'using proxy @{proxy} for @{url}'\n );\n }\n }\n}\n\nexport { ProxyStorage };\n"],"mappings":"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"}
package/build/proxy.mjs CHANGED
@@ -3,7 +3,7 @@ import { parseInterval } from "./proxy-utils.mjs";
3
3
  import JSONStream from "JSONStream";
4
4
  import buildDebug from "debug";
5
5
  import got, { Options } from "got";
6
- import _ from "lodash";
6
+ import { isNil, isObject } from "lodash-es";
7
7
  import { PassThrough, Readable } from "node:stream";
8
8
  import { URL } from "node:url";
9
9
  import { API_ERROR, HEADERS, HTTP_STATUS, TOKEN_BASIC, TOKEN_BEARER, authUtils, constants, errorUtils } from "@verdaccio/core";
@@ -17,7 +17,7 @@ var contentTypeAccept = `${HEADERS.JSON};`;
17
17
  * Just a helper (`config[key] || default` doesn't work because of zeroes)
18
18
  */
19
19
  var setConfig = (config, key, def) => {
20
- return _.isNil(config[key]) === false ? config[key] : def;
20
+ return isNil(config[key]) === false ? config[key] : def;
21
21
  };
22
22
  /**
23
23
  * Implements Storage interface
@@ -96,13 +96,13 @@ var ProxyStorage = class {
96
96
  setAuthNext(headers) {
97
97
  const { auth } = this.config;
98
98
  if (typeof auth === "undefined" || typeof headers[HEADERS.AUTHORIZATION] === "string") return headers;
99
- if (_.isObject(auth) === false && _.isObject(auth.token) === false) this._throwErrorAuth("Auth invalid");
99
+ if (isObject(auth) === false && isObject(auth.token) === false) this._throwErrorAuth("Auth invalid");
100
100
  let token;
101
101
  const tokenConf = auth;
102
- if (_.isNil(tokenConf.token) === false && _.isString(tokenConf.token)) {
102
+ if (isNil(tokenConf.token) === false && typeof tokenConf.token === "string") {
103
103
  debug("use token from config");
104
104
  token = tokenConf.token;
105
- } else if (_.isNil(tokenConf.token_env) === false) if (typeof tokenConf.token_env === "string") {
105
+ } else if (isNil(tokenConf.token_env) === false) if (typeof tokenConf.token_env === "string") {
106
106
  debug("use token from env %o", tokenConf.token_env);
107
107
  token = process.env[tokenConf.token_env];
108
108
  } else if (typeof tokenConf.token_env === "boolean" && tokenConf.token_env) {
@@ -173,7 +173,7 @@ var ProxyStorage = class {
173
173
  let headers = this.getHeaders(options?.headers);
174
174
  headers = this.addProxyHeaders(headers, options.remoteAddress);
175
175
  headers = this.applyUplinkHeaders(headers);
176
- if (_.isNil(options.etag) === false) {
176
+ if (isNil(options.etag) === false) {
177
177
  headers[HEADERS.NONE_MATCH] = options.etag;
178
178
  headers[HEADERS.ACCEPT] = contentTypeAccept;
179
179
  }
@@ -226,7 +226,7 @@ var ProxyStorage = class {
226
226
  method,
227
227
  url: uri
228
228
  },
229
- status: _.isNull(eventResponse) === false ? eventResponse.statusCode : "ERR"
229
+ status: eventResponse !== null ? eventResponse.statusCode : "ERR"
230
230
  }, "@{!status}, req: '@{request.method} @{request.url}' (streaming)");
231
231
  }).on("downloadProgress", (progress) => {
232
232
  if (progress.total) {
@@ -281,7 +281,7 @@ var ProxyStorage = class {
281
281
  let headers = this.getHeaders(options?.headers);
282
282
  headers = this.addProxyHeaders(headers, options.remoteAddress);
283
283
  headers = this.applyUplinkHeaders(headers);
284
- if (_.isNil(options.etag) === false) {
284
+ if (isNil(options.etag) === false) {
285
285
  headers[HEADERS.NONE_MATCH] = options.etag;
286
286
  headers[HEADERS.ACCEPT] = contentTypeAccept;
287
287
  }
@@ -375,8 +375,8 @@ var ProxyStorage = class {
375
375
  if ("no_proxy" in config) noProxyList = config.no_proxy;
376
376
  else if ("no_proxy" in mainconfig) noProxyList = mainconfig.no_proxy;
377
377
  if (hostname[0] !== ".") hostname = "." + hostname;
378
- if (_.isString(noProxyList) && noProxyList.length) noProxyList = noProxyList.split(",");
379
- if (_.isArray(noProxyList)) for (let i = 0; i < noProxyList.length; i++) {
378
+ if (typeof noProxyList === "string" && noProxyList.length) noProxyList = noProxyList.split(",");
379
+ if (Array.isArray(noProxyList)) for (let i = 0; i < noProxyList.length; i++) {
380
380
  let noProxyItem = noProxyList[i];
381
381
  if (noProxyItem[0] !== ".") noProxyItem = "." + noProxyItem;
382
382
  if (hostname.endsWith(noProxyItem)) {
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.mjs","names":[],"sources":["../src/proxy.ts"],"sourcesContent":["import JSONStream from 'JSONStream';\nimport buildDebug from 'debug';\nimport type { Agents, Delays, RequestError, RetryOptions, Headers as gotHeaders } from 'got';\nimport got, { Options } from 'got';\nimport _ from 'lodash';\nimport type Stream from 'node:stream';\nimport { PassThrough, Readable } from 'node:stream';\nimport { URL } from 'node:url';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n HEADERS,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n authUtils,\n constants,\n errorUtils,\n} from '@verdaccio/core';\nimport type { AgentOptionsConf, Config, Logger, Manifest, UpLinkConf } from '@verdaccio/types';\n\nimport CustomAgents from './agent';\nimport { parseInterval } from './proxy-utils';\n\nconst debug = buildDebug('verdaccio:proxy');\n\nconst encode = function (thing): string {\n return encodeURIComponent(thing).replace(/^%40/, '@');\n};\n\nconst jsonContentType = HEADERS.JSON;\nconst contentTypeAccept = `${jsonContentType};`;\n\n/**\n * Just a helper (`config[key] || default` doesn't work because of zeroes)\n */\nconst setConfig = (config: UpLinkConfLocal, key: string, def): string => {\n return _.isNil(config[key]) === false ? config[key] : def;\n};\n\nexport type UpLinkConfLocal = UpLinkConf & {\n no_proxy?: string;\n};\n\nexport interface ProxyList {\n [key: string]: IProxy;\n}\n\nexport type ProxySearchParams = {\n url: string;\n abort: AbortController;\n query?: searchUtils.SearchQuery;\n headers?: Headers;\n retry?: Partial<RetryOptions>;\n};\nexport interface IProxy {\n uplinkName: string;\n config: UpLinkConfLocal;\n failed_requests: number;\n userAgent: string;\n ca?: string | void;\n logger: Logger;\n server_id: string;\n url: URL;\n maxage: number;\n timeout: Delays;\n max_fails: number;\n fail_timeout: number;\n search(options: ProxySearchParams): Promise<Stream.Readable>;\n getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]>;\n fetchTarball(\n url: string,\n options: Partial<Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>>\n ): PassThrough;\n}\n\n// this type is need it by storage\nexport { Options as FetchOptions };\n\nexport interface ISyncUplinksOptions extends Options {\n uplinksLook?: boolean;\n etag?: string;\n remoteAddress?: string;\n}\n\n/**\n * Implements Storage interface\n * (same for storage.js, local-storage.js, up-storage.js)\n */\nclass ProxyStorage implements IProxy {\n public uplinkName: string;\n public config: UpLinkConfLocal;\n public failed_requests: number;\n public userAgent: string;\n public ca: string | void;\n public logger: Logger;\n public server_id: string;\n public url: URL;\n public maxage: number;\n public timeout: Delays;\n public max_fails: number;\n public fail_timeout: number;\n public agent_options: AgentOptionsConf;\n public proxy: string | undefined;\n private agent: Agents;\n // @ts-ignore\n public last_request_time: number | null;\n public strict_ssl: boolean;\n private retry: Partial<RetryOptions>;\n\n public constructor(\n uplinkName: string,\n config: UpLinkConfLocal,\n mainConfig: Config,\n logger: Logger,\n agent?: Agents\n ) {\n this.uplinkName = uplinkName;\n this.config = config;\n this.failed_requests = 0;\n this.userAgent = mainConfig.user_agent ?? 'hidden';\n this.ca = config.ca;\n this.logger = logger;\n this.server_id = mainConfig.server_id;\n this.agent_options = setConfig(this.config, 'agent_options', {\n keepAlive: true,\n maxSockets: 40,\n maxFreeSockets: 10,\n }) as AgentOptionsConf;\n this.url = new URL(this.config.url);\n const isHTTPS = this.url.protocol === 'https:';\n this._setupProxy(this.url.hostname, config, mainConfig, isHTTPS);\n this.agent = agent ?? this.getAgent();\n this.config.url = this.config.url.replace(/\\/$/, '');\n\n if (this.config.timeout && Number(this.config.timeout) >= 1000) {\n this.logger.warn(\n [\n 'Too big timeout value: ' + this.config.timeout,\n 'We changed time format to nginx-like one',\n '(see http://nginx.org/en/docs/syntax.html)',\n 'so please update your config accordingly',\n ].join('\\n')\n );\n }\n\n // a bunch of different configurable timers\n this.maxage = parseInterval(setConfig(this.config, 'maxage', '2m'));\n // https://github.com/sindresorhus/got/blob/main/documentation/6-timeout.md\n this.timeout = {\n request: parseInterval(setConfig(this.config, 'timeout', '30s')),\n };\n debug('set timeout %s', this.timeout);\n this.max_fails = Number(setConfig(this.config, 'max_fails', this.config.max_fails ?? 2));\n this.fail_timeout = parseInterval(setConfig(this.config, 'fail_timeout', '5m'));\n this.strict_ssl = Boolean(setConfig(this.config, 'strict_ssl', true));\n this.retry = { limit: this.max_fails ?? 2 };\n }\n\n private getAgent() {\n if (!this.agent) {\n // TODO: the config.ca (certificates) is not yet injected here\n const agentInstance = new CustomAgents(this.config.url, this.proxy, this.agent_options);\n return agentInstance.get();\n } else {\n return this.agent;\n }\n }\n\n public getHeaders(headers = {}): gotHeaders {\n const accept = HEADERS.ACCEPT;\n const acceptEncoding = HEADERS.ACCEPT_ENCODING;\n const userAgent = HEADERS.USER_AGENT;\n\n headers[accept] = headers[accept] || contentTypeAccept;\n headers[acceptEncoding] = headers[acceptEncoding] || 'gzip';\n // registry.npmjs.org will only return search result if user-agent include string 'npm'\n headers[userAgent] = headers[userAgent] || `npm (${this.userAgent})`;\n return this.setAuthNext(headers);\n }\n\n /**\n * Validate configuration auth and assign Header authorization\n * @param {Object} headers\n * @return {Object}\n * @private\n */\n private setAuthNext(headers: gotHeaders): gotHeaders {\n const { auth } = this.config;\n if (typeof auth === 'undefined' || typeof headers[HEADERS.AUTHORIZATION] === 'string') {\n return headers;\n }\n\n if (_.isObject(auth) === false && _.isObject((auth as any).token) === false) {\n this._throwErrorAuth('Auth invalid');\n }\n\n // get NPM_TOKEN http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules\n // or get other variable export in env\n // https://github.com/verdaccio/verdaccio/releases/tag/v2.5.0\n let token: any;\n const tokenConf: any = auth;\n if (_.isNil(tokenConf.token) === false && _.isString(tokenConf.token)) {\n debug('use token from config');\n token = tokenConf.token;\n } else if (_.isNil(tokenConf.token_env) === false) {\n if (typeof tokenConf.token_env === 'string') {\n debug('use token from env %o', tokenConf.token_env);\n token = process.env[tokenConf.token_env];\n } else if (typeof tokenConf.token_env === 'boolean' && tokenConf.token_env) {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n } else {\n this.logger.error(constants.ERROR_CODE.token_required);\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n } else {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n }\n\n if (typeof token === 'undefined') {\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n\n // define type Auth allow basic and bearer\n const type = tokenConf.type || TOKEN_BASIC;\n debug('token type %o', type);\n this._setHeaderAuthorization(headers, type, token);\n\n return headers;\n }\n\n /**\n * @param {string} message\n * @throws {Error}\n * @private\n */\n private _throwErrorAuth(message: string): Error {\n this.logger.error(message);\n throw new Error(message);\n }\n\n /**\n * Assign Header authorization with type authentication\n * @param {Object} headers\n * @param {string} type\n * @param {string} token\n * @private\n */\n private _setHeaderAuthorization(headers: any, type: string, token: any): void {\n const _type: string = type.toLowerCase();\n\n if (_type !== TOKEN_BEARER.toLowerCase() && _type !== TOKEN_BASIC.toLowerCase()) {\n this._throwErrorAuth(`Auth type '${_type}' not allowed`);\n }\n\n headers[HEADERS.AUTHORIZATION] = authUtils.buildToken(type, token);\n }\n\n /**\n * It will add or override specified headers from config file.\n *\n * Eg:\n *\n * uplinks:\n npmjs:\n url: https://registry.npmjs.org/\n headers:\n Accept: \"application/vnd.npm.install-v2+json; q=1.0\"\n verdaccio-staging:\n url: https://mycompany.com/npm\n headers:\n Accept: \"application/json\"\n authorization: \"Basic YourBase64EncodedCredentials==\"\n\n * @param {Object} headers\n * @private\n */\n private applyUplinkHeaders(headers: gotHeaders): gotHeaders {\n if (!this.config.headers) {\n return headers;\n }\n\n // add/override headers specified in the config\n /* eslint guard-for-in: 0 */\n for (const key in this.config.headers) {\n headers[key] = this.config.headers[key];\n }\n return headers;\n }\n\n public async getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]> {\n if (this._ifRequestFailure()) {\n throw errorUtils.getInternalError(API_ERROR.UPLINK_OFFLINE);\n }\n\n // FUTURE: allow mix headers that comes from the client\n debug('getting metadata for package %s', name);\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (_.isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = options.method || 'GET';\n const uri = this.config.url + `/${encode(name)}`;\n debug('set retry limit is %s', this.retry.limit);\n let response;\n let responseLength = 0;\n try {\n const retry = options?.retry ?? this.retry;\n debug('retry initial count %s', retry);\n response = await got(uri, {\n headers,\n responseType: 'json',\n method,\n agent: this.agent,\n retry,\n timeout: this.timeout,\n hooks: {\n afterResponse: [\n (afterResponse) => {\n const code = afterResponse.statusCode;\n debug('after response code is %s', code);\n if (code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES) {\n if (this.failed_requests >= this.max_fails) {\n this.failed_requests = 0;\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now online'\n );\n }\n }\n\n return afterResponse;\n },\n ],\n beforeRetry: [\n (error: RequestError, count: number) => {\n debug('retry %s count: %s', uri, count);\n this.failed_requests = count ?? 0;\n this.logger.info(\n {\n request: {\n method: method,\n url: uri,\n },\n error: error.message,\n retryCount: this.failed_requests,\n },\n \"retry @{retryCount} req: '@{request.method} @{request.url}'\"\n );\n if (this.failed_requests >= this.max_fails) {\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now offline'\n );\n }\n },\n ],\n },\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n })\n .on<any>('response', (eventResponse) => {\n const message = \"@{!status}, req: '@{request.method} @{request.url}' (streaming)\";\n this.logger.http(\n {\n request: {\n method: method,\n url: uri,\n },\n status: _.isNull(eventResponse) === false ? eventResponse.statusCode : 'ERR',\n },\n message\n );\n })\n .on('downloadProgress', (progress) => {\n if (progress.total) {\n debug('responseLength %s', progress.total);\n responseLength = progress.total;\n }\n });\n const etag = response.headers.etag as string;\n const data = response.body;\n\n // not modified status (304) registry does not return any payload\n // it is handled as an error with the original 304 status preserved\n if (response?.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n const err = errorUtils.getNotFound(API_ERROR.NOT_MODIFIED_NO_DATA);\n err.code = HTTP_STATUS.NOT_MODIFIED;\n throw err;\n }\n\n debug('uri %s success', uri);\n const message = \"@{!status}, req: '@{request.method} @{request.url}'\";\n this.logger.http(\n {\n // if error is null/false change this to undefined so it wont log\n request: { method: method, url: uri },\n status: response.statusCode,\n bytes: {\n in: options?.json ? JSON.stringify(options?.json).length : 0,\n out: responseLength || 0,\n },\n },\n message\n );\n return [data, etag];\n } catch (err: any) {\n debug('error %s on uri %s', err.code, uri);\n if (err.code === 'ERR_NON_2XX_3XX_RESPONSE') {\n const code = err.response.statusCode;\n debug('error code %s', code);\n if (code === HTTP_STATUS.NOT_FOUND) {\n throw errorUtils.getNotFound(API_ERROR.NOT_PACKAGE_UPLINK);\n }\n\n if (!(code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES)) {\n const error = errorUtils.getInternalError(`${API_ERROR.BAD_STATUS_CODE}: ${code}`);\n // we need this code to identify outside which status code triggered the error\n error.remoteStatus = code;\n throw error;\n }\n } else if (this._isRequestTimeout(err)) {\n debug('error code timeout');\n throw errorUtils.getServiceUnavailable(API_ERROR.SERVER_TIME_OUT);\n }\n throw err;\n }\n }\n\n // FIXME: handle stream and retry\n public fetchTarball(\n url: string,\n overrideOptions: Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>\n ): any {\n debug('fetching url for %s', url);\n const options = { ...this.config, ...overrideOptions };\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (_.isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = 'GET';\n // const uri = this.config.url + `/${encode(name)}`;\n debug('request uri for %s', url);\n\n const readStream = got\n .stream(url, {\n headers,\n method,\n agent: this.agent,\n // FIXME: this should be taken from construtor as priority\n retry: this.retry ?? options?.retry,\n timeout: this.timeout,\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n });\n\n return readStream;\n }\n\n /**\n * Perform a stream search.\n * @param {*} options request options\n * @return {Stream}\n */\n public async search({ url, abort, retry }: ProxySearchParams): Promise<Stream.Readable> {\n try {\n // Incoming URL is relative ie /-/v1/search...\n const uri = new URL(url, this.url).href;\n this.logger.http(\n { uri, uplink: this.uplinkName },\n 'search request to uplink @{uplink} - @{uri}'\n );\n debug('searching on %o', uri);\n const response = got(uri, {\n signal: abort ? abort.signal : {},\n agent: this.agent,\n timeout: this.timeout,\n retry: retry ?? this.retry,\n });\n\n const res = await response.text();\n const total = JSON.parse(res).total;\n debug('number of packages found: %o', total);\n const streamSearch = new PassThrough({ objectMode: true });\n const streamResponse = Readable.from(res);\n // objects is one of the properties on the body, it ignores date and total\n streamResponse.pipe(JSONStream.parse('objects')).pipe(streamSearch, { end: true });\n return streamSearch;\n } catch (err: any) {\n debug('search error %s', err);\n if (err.response.statusCode === 409) {\n throw errorUtils.getInternalError(`bad status code ${err.response.statusCode} from uplink`);\n }\n this.logger.error(\n { errorMessage: err?.message, name: this.uplinkName },\n 'proxy uplink @{name} search error: @{errorMessage}'\n );\n throw err;\n }\n }\n\n private addProxyHeaders(headers: gotHeaders, remoteAddress?: string): gotHeaders {\n // Only submit X-Forwarded-For field if we don't have a proxy selected\n // in the config file.\n //\n // Otherwise misconfigured proxy could return 407\n if (!this.proxy) {\n headers[HEADERS.FORWARDED_FOR] =\n (headers['x-forwarded-for'] ? headers['x-forwarded-for'] + ', ' : '') + remoteAddress;\n }\n\n // always attach Via header to avoid loops, even if we're not proxying\n headers['via'] = headers['via'] ? headers['via'] + ', ' : '';\n headers['via'] += '1.1 ' + this.server_id + ' (Verdaccio)';\n\n return headers;\n }\n\n /**\n * If the request failure.\n * @return {boolean}\n * @private\n */\n private _ifRequestFailure(): boolean {\n return (\n this.failed_requests >= this.max_fails &&\n Math.abs(Date.now() - (this.last_request_time as number)) < this.fail_timeout\n );\n }\n\n /**\n * Check if the request timed out (network or http errors).\n * @param {RequestError} err\n * @return {boolean}\n */\n private _isRequestTimeout(err: RequestError): boolean {\n const code = err?.response?.statusCode;\n return (\n err.code === 'ETIMEDOUT' ||\n err.code === 'ESOCKETTIMEDOUT' ||\n err.code === 'ECONNRESET' ||\n code === HTTP_STATUS.REQUEST_TIMEOUT ||\n code === HTTP_STATUS.BAD_GATEWAY ||\n code === HTTP_STATUS.SERVICE_UNAVAILABLE ||\n code === HTTP_STATUS.GATEWAY_TIMEOUT\n );\n }\n\n /**\n * Set up a proxy.\n * @param {*} hostname\n * @param {*} config\n * @param {*} mainconfig\n * @param {*} isHTTPS\n */\n private _setupProxy(\n hostname: string,\n config: UpLinkConfLocal,\n mainconfig: Config,\n isHTTPS: boolean\n ): void {\n let noProxyList;\n const proxy_key: string = isHTTPS ? 'https_proxy' : 'http_proxy';\n debug('looking for %o', proxy_key);\n\n // get http_proxy and no_proxy configs\n if (proxy_key in config) {\n this.proxy = config[proxy_key];\n debug('found %o in uplink config', this.proxy);\n } else if (proxy_key in mainconfig) {\n this.proxy = mainconfig[proxy_key];\n debug('found %o in main config', this.proxy);\n }\n if ('no_proxy' in config) {\n noProxyList = config.no_proxy;\n } else if ('no_proxy' in mainconfig) {\n noProxyList = mainconfig.no_proxy;\n }\n\n // use wget-like algorithm to determine if proxy shouldn't be used\n if (hostname[0] !== '.') {\n hostname = '.' + hostname;\n }\n\n if (_.isString(noProxyList) && noProxyList.length) {\n noProxyList = noProxyList.split(',');\n }\n\n if (_.isArray(noProxyList)) {\n for (let i = 0; i < noProxyList.length; i++) {\n let noProxyItem = noProxyList[i];\n if (noProxyItem[0] !== '.') {\n noProxyItem = '.' + noProxyItem;\n }\n if (hostname.endsWith(noProxyItem)) {\n if (this.proxy) {\n debug('not using proxy, excluded by @{rule}', noProxyItem);\n this.logger.debug(\n { url: this.url.href, rule: noProxyItem },\n 'not using proxy for @{url}, excluded by @{rule} rule'\n );\n this.proxy = undefined;\n }\n break;\n }\n }\n }\n\n if (typeof this.proxy === 'string') {\n debug('using proxy @{proxy} for @{url}', this.proxy, this.url.href);\n this.logger.debug(\n { url: this.url.href, proxy: this.proxy },\n 'using proxy @{proxy} for @{url}'\n );\n }\n }\n}\n\nexport { ProxyStorage };\n"],"mappings":"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"}
1
+ {"version":3,"file":"proxy.mjs","names":[],"sources":["../src/proxy.ts"],"sourcesContent":["import JSONStream from 'JSONStream';\nimport buildDebug from 'debug';\nimport type { Agents, Delays, RequestError, RetryOptions, Headers as gotHeaders } from 'got';\nimport got, { Options } from 'got';\nimport { isNil, isObject } from 'lodash-es';\nimport type Stream from 'node:stream';\nimport { PassThrough, Readable } from 'node:stream';\nimport { URL } from 'node:url';\n\nimport type { searchUtils } from '@verdaccio/core';\nimport {\n API_ERROR,\n HEADERS,\n HTTP_STATUS,\n TOKEN_BASIC,\n TOKEN_BEARER,\n authUtils,\n constants,\n errorUtils,\n} from '@verdaccio/core';\nimport type { AgentOptionsConf, Config, Logger, Manifest, UpLinkConf } from '@verdaccio/types';\n\nimport CustomAgents from './agent';\nimport { parseInterval } from './proxy-utils';\n\nconst debug = buildDebug('verdaccio:proxy');\n\nconst encode = function (thing): string {\n return encodeURIComponent(thing).replace(/^%40/, '@');\n};\n\nconst jsonContentType = HEADERS.JSON;\nconst contentTypeAccept = `${jsonContentType};`;\n\n/**\n * Just a helper (`config[key] || default` doesn't work because of zeroes)\n */\nconst setConfig = (config: UpLinkConfLocal, key: string, def): string => {\n return isNil(config[key]) === false ? config[key] : def;\n};\n\nexport type UpLinkConfLocal = UpLinkConf & {\n no_proxy?: string;\n};\n\nexport interface ProxyList {\n [key: string]: IProxy;\n}\n\nexport type ProxySearchParams = {\n url: string;\n abort: AbortController;\n query?: searchUtils.SearchQuery;\n headers?: Headers;\n retry?: Partial<RetryOptions>;\n};\nexport interface IProxy {\n uplinkName: string;\n config: UpLinkConfLocal;\n failed_requests: number;\n userAgent: string;\n ca?: string | void;\n logger: Logger;\n server_id: string;\n url: URL;\n maxage: number;\n timeout: Delays;\n max_fails: number;\n fail_timeout: number;\n search(options: ProxySearchParams): Promise<Stream.Readable>;\n getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]>;\n fetchTarball(\n url: string,\n options: Partial<Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>>\n ): PassThrough;\n}\n\n// this type is need it by storage\nexport { Options as FetchOptions };\n\nexport interface ISyncUplinksOptions extends Options {\n uplinksLook?: boolean;\n etag?: string;\n remoteAddress?: string;\n}\n\n/**\n * Implements Storage interface\n * (same for storage.js, local-storage.js, up-storage.js)\n */\nclass ProxyStorage implements IProxy {\n public uplinkName: string;\n public config: UpLinkConfLocal;\n public failed_requests: number;\n public userAgent: string;\n public ca: string | void;\n public logger: Logger;\n public server_id: string;\n public url: URL;\n public maxage: number;\n public timeout: Delays;\n public max_fails: number;\n public fail_timeout: number;\n public agent_options: AgentOptionsConf;\n public proxy: string | undefined;\n private agent: Agents;\n // @ts-ignore\n public last_request_time: number | null;\n public strict_ssl: boolean;\n private retry: Partial<RetryOptions>;\n\n public constructor(\n uplinkName: string,\n config: UpLinkConfLocal,\n mainConfig: Config,\n logger: Logger,\n agent?: Agents\n ) {\n this.uplinkName = uplinkName;\n this.config = config;\n this.failed_requests = 0;\n this.userAgent = mainConfig.user_agent ?? 'hidden';\n this.ca = config.ca;\n this.logger = logger;\n this.server_id = mainConfig.server_id;\n this.agent_options = setConfig(this.config, 'agent_options', {\n keepAlive: true,\n maxSockets: 40,\n maxFreeSockets: 10,\n }) as AgentOptionsConf;\n this.url = new URL(this.config.url);\n const isHTTPS = this.url.protocol === 'https:';\n this._setupProxy(this.url.hostname, config, mainConfig, isHTTPS);\n this.agent = agent ?? this.getAgent();\n this.config.url = this.config.url.replace(/\\/$/, '');\n\n if (this.config.timeout && Number(this.config.timeout) >= 1000) {\n this.logger.warn(\n [\n 'Too big timeout value: ' + this.config.timeout,\n 'We changed time format to nginx-like one',\n '(see http://nginx.org/en/docs/syntax.html)',\n 'so please update your config accordingly',\n ].join('\\n')\n );\n }\n\n // a bunch of different configurable timers\n this.maxage = parseInterval(setConfig(this.config, 'maxage', '2m'));\n // https://github.com/sindresorhus/got/blob/main/documentation/6-timeout.md\n this.timeout = {\n request: parseInterval(setConfig(this.config, 'timeout', '30s')),\n };\n debug('set timeout %s', this.timeout);\n this.max_fails = Number(setConfig(this.config, 'max_fails', this.config.max_fails ?? 2));\n this.fail_timeout = parseInterval(setConfig(this.config, 'fail_timeout', '5m'));\n this.strict_ssl = Boolean(setConfig(this.config, 'strict_ssl', true));\n this.retry = { limit: this.max_fails ?? 2 };\n }\n\n private getAgent() {\n if (!this.agent) {\n // TODO: the config.ca (certificates) is not yet injected here\n const agentInstance = new CustomAgents(this.config.url, this.proxy, this.agent_options);\n return agentInstance.get();\n } else {\n return this.agent;\n }\n }\n\n public getHeaders(headers = {}): gotHeaders {\n const accept = HEADERS.ACCEPT;\n const acceptEncoding = HEADERS.ACCEPT_ENCODING;\n const userAgent = HEADERS.USER_AGENT;\n\n headers[accept] = headers[accept] || contentTypeAccept;\n headers[acceptEncoding] = headers[acceptEncoding] || 'gzip';\n // registry.npmjs.org will only return search result if user-agent include string 'npm'\n headers[userAgent] = headers[userAgent] || `npm (${this.userAgent})`;\n return this.setAuthNext(headers);\n }\n\n /**\n * Validate configuration auth and assign Header authorization\n * @param {Object} headers\n * @return {Object}\n * @private\n */\n private setAuthNext(headers: gotHeaders): gotHeaders {\n const { auth } = this.config;\n if (typeof auth === 'undefined' || typeof headers[HEADERS.AUTHORIZATION] === 'string') {\n return headers;\n }\n\n if (isObject(auth) === false && isObject((auth as any).token) === false) {\n this._throwErrorAuth('Auth invalid');\n }\n\n // get NPM_TOKEN http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules\n // or get other variable export in env\n // https://github.com/verdaccio/verdaccio/releases/tag/v2.5.0\n let token: any;\n const tokenConf: any = auth;\n if (isNil(tokenConf.token) === false && typeof tokenConf.token === 'string') {\n debug('use token from config');\n token = tokenConf.token;\n } else if (isNil(tokenConf.token_env) === false) {\n if (typeof tokenConf.token_env === 'string') {\n debug('use token from env %o', tokenConf.token_env);\n token = process.env[tokenConf.token_env];\n } else if (typeof tokenConf.token_env === 'boolean' && tokenConf.token_env) {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n } else {\n this.logger.error(constants.ERROR_CODE.token_required);\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n } else {\n debug('use token from env NPM_TOKEN');\n token = process.env.NPM_TOKEN;\n }\n\n if (typeof token === 'undefined') {\n this._throwErrorAuth(constants.ERROR_CODE.token_required);\n }\n\n // define type Auth allow basic and bearer\n const type = tokenConf.type || TOKEN_BASIC;\n debug('token type %o', type);\n this._setHeaderAuthorization(headers, type, token);\n\n return headers;\n }\n\n /**\n * @param {string} message\n * @throws {Error}\n * @private\n */\n private _throwErrorAuth(message: string): Error {\n this.logger.error(message);\n throw new Error(message);\n }\n\n /**\n * Assign Header authorization with type authentication\n * @param {Object} headers\n * @param {string} type\n * @param {string} token\n * @private\n */\n private _setHeaderAuthorization(headers: any, type: string, token: any): void {\n const _type: string = type.toLowerCase();\n\n if (_type !== TOKEN_BEARER.toLowerCase() && _type !== TOKEN_BASIC.toLowerCase()) {\n this._throwErrorAuth(`Auth type '${_type}' not allowed`);\n }\n\n headers[HEADERS.AUTHORIZATION] = authUtils.buildToken(type, token);\n }\n\n /**\n * It will add or override specified headers from config file.\n *\n * Eg:\n *\n * uplinks:\n npmjs:\n url: https://registry.npmjs.org/\n headers:\n Accept: \"application/vnd.npm.install-v2+json; q=1.0\"\n verdaccio-staging:\n url: https://mycompany.com/npm\n headers:\n Accept: \"application/json\"\n authorization: \"Basic YourBase64EncodedCredentials==\"\n\n * @param {Object} headers\n * @private\n */\n private applyUplinkHeaders(headers: gotHeaders): gotHeaders {\n if (!this.config.headers) {\n return headers;\n }\n\n // add/override headers specified in the config\n /* eslint guard-for-in: 0 */\n for (const key in this.config.headers) {\n headers[key] = this.config.headers[key];\n }\n return headers;\n }\n\n public async getRemoteMetadata(\n name: string,\n options: Partial<ISyncUplinksOptions>\n ): Promise<[Manifest, string]> {\n if (this._ifRequestFailure()) {\n throw errorUtils.getInternalError(API_ERROR.UPLINK_OFFLINE);\n }\n\n // FUTURE: allow mix headers that comes from the client\n debug('getting metadata for package %s', name);\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = options.method || 'GET';\n const uri = this.config.url + `/${encode(name)}`;\n debug('set retry limit is %s', this.retry.limit);\n let response;\n let responseLength = 0;\n try {\n const retry = options?.retry ?? this.retry;\n debug('retry initial count %s', retry);\n response = await got(uri, {\n headers,\n responseType: 'json',\n method,\n agent: this.agent,\n retry,\n timeout: this.timeout,\n hooks: {\n afterResponse: [\n (afterResponse) => {\n const code = afterResponse.statusCode;\n debug('after response code is %s', code);\n if (code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES) {\n if (this.failed_requests >= this.max_fails) {\n this.failed_requests = 0;\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now online'\n );\n }\n }\n\n return afterResponse;\n },\n ],\n beforeRetry: [\n (error: RequestError, count: number) => {\n debug('retry %s count: %s', uri, count);\n this.failed_requests = count ?? 0;\n this.logger.info(\n {\n request: {\n method: method,\n url: uri,\n },\n error: error.message,\n retryCount: this.failed_requests,\n },\n \"retry @{retryCount} req: '@{request.method} @{request.url}'\"\n );\n if (this.failed_requests >= this.max_fails) {\n this.logger.warn(\n {\n host: this.url.host,\n },\n 'host @{host} is now offline'\n );\n }\n },\n ],\n },\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n })\n .on<any>('response', (eventResponse) => {\n const message = \"@{!status}, req: '@{request.method} @{request.url}' (streaming)\";\n this.logger.http(\n {\n request: {\n method: method,\n url: uri,\n },\n status: eventResponse !== null ? eventResponse.statusCode : 'ERR',\n },\n message\n );\n })\n .on('downloadProgress', (progress) => {\n if (progress.total) {\n debug('responseLength %s', progress.total);\n responseLength = progress.total;\n }\n });\n const etag = response.headers.etag as string;\n const data = response.body;\n\n // not modified status (304) registry does not return any payload\n // it is handled as an error with the original 304 status preserved\n if (response?.statusCode === HTTP_STATUS.NOT_MODIFIED) {\n const err = errorUtils.getNotFound(API_ERROR.NOT_MODIFIED_NO_DATA);\n err.code = HTTP_STATUS.NOT_MODIFIED;\n throw err;\n }\n\n debug('uri %s success', uri);\n const message = \"@{!status}, req: '@{request.method} @{request.url}'\";\n this.logger.http(\n {\n // if error is null/false change this to undefined so it wont log\n request: { method: method, url: uri },\n status: response.statusCode,\n bytes: {\n in: options?.json ? JSON.stringify(options?.json).length : 0,\n out: responseLength || 0,\n },\n },\n message\n );\n return [data, etag];\n } catch (err: any) {\n debug('error %s on uri %s', err.code, uri);\n if (err.code === 'ERR_NON_2XX_3XX_RESPONSE') {\n const code = err.response.statusCode;\n debug('error code %s', code);\n if (code === HTTP_STATUS.NOT_FOUND) {\n throw errorUtils.getNotFound(API_ERROR.NOT_PACKAGE_UPLINK);\n }\n\n if (!(code >= HTTP_STATUS.OK && code < HTTP_STATUS.MULTIPLE_CHOICES)) {\n const error = errorUtils.getInternalError(`${API_ERROR.BAD_STATUS_CODE}: ${code}`);\n // we need this code to identify outside which status code triggered the error\n error.remoteStatus = code;\n throw error;\n }\n } else if (this._isRequestTimeout(err)) {\n debug('error code timeout');\n throw errorUtils.getServiceUnavailable(API_ERROR.SERVER_TIME_OUT);\n }\n throw err;\n }\n }\n\n // FIXME: handle stream and retry\n public fetchTarball(\n url: string,\n overrideOptions: Pick<ISyncUplinksOptions, 'remoteAddress' | 'etag' | 'retry'>\n ): any {\n debug('fetching url for %s', url);\n const options = { ...this.config, ...overrideOptions };\n let headers = this.getHeaders(options?.headers);\n headers = this.addProxyHeaders(headers, options.remoteAddress);\n headers = this.applyUplinkHeaders(headers);\n // the following headers cannot be overwritten\n if (isNil(options.etag) === false) {\n headers[HEADERS.NONE_MATCH] = options.etag;\n headers[HEADERS.ACCEPT] = contentTypeAccept;\n }\n const method = 'GET';\n // const uri = this.config.url + `/${encode(name)}`;\n debug('request uri for %s', url);\n\n const readStream = got\n .stream(url, {\n headers,\n method,\n agent: this.agent,\n // FIXME: this should be taken from construtor as priority\n retry: this.retry ?? options?.retry,\n timeout: this.timeout,\n })\n .on('request', () => {\n this.last_request_time = Date.now();\n });\n\n return readStream;\n }\n\n /**\n * Perform a stream search.\n * @param {*} options request options\n * @return {Stream}\n */\n public async search({ url, abort, retry }: ProxySearchParams): Promise<Stream.Readable> {\n try {\n // Incoming URL is relative ie /-/v1/search...\n const uri = new URL(url, this.url).href;\n this.logger.http(\n { uri, uplink: this.uplinkName },\n 'search request to uplink @{uplink} - @{uri}'\n );\n debug('searching on %o', uri);\n const response = got(uri, {\n signal: abort ? abort.signal : {},\n agent: this.agent,\n timeout: this.timeout,\n retry: retry ?? this.retry,\n });\n\n const res = await response.text();\n const total = JSON.parse(res).total;\n debug('number of packages found: %o', total);\n const streamSearch = new PassThrough({ objectMode: true });\n const streamResponse = Readable.from(res);\n // objects is one of the properties on the body, it ignores date and total\n streamResponse.pipe(JSONStream.parse('objects')).pipe(streamSearch, { end: true });\n return streamSearch;\n } catch (err: any) {\n debug('search error %s', err);\n if (err.response.statusCode === 409) {\n throw errorUtils.getInternalError(`bad status code ${err.response.statusCode} from uplink`);\n }\n this.logger.error(\n { errorMessage: err?.message, name: this.uplinkName },\n 'proxy uplink @{name} search error: @{errorMessage}'\n );\n throw err;\n }\n }\n\n private addProxyHeaders(headers: gotHeaders, remoteAddress?: string): gotHeaders {\n // Only submit X-Forwarded-For field if we don't have a proxy selected\n // in the config file.\n //\n // Otherwise misconfigured proxy could return 407\n if (!this.proxy) {\n headers[HEADERS.FORWARDED_FOR] =\n (headers['x-forwarded-for'] ? headers['x-forwarded-for'] + ', ' : '') + remoteAddress;\n }\n\n // always attach Via header to avoid loops, even if we're not proxying\n headers['via'] = headers['via'] ? headers['via'] + ', ' : '';\n headers['via'] += '1.1 ' + this.server_id + ' (Verdaccio)';\n\n return headers;\n }\n\n /**\n * If the request failure.\n * @return {boolean}\n * @private\n */\n private _ifRequestFailure(): boolean {\n return (\n this.failed_requests >= this.max_fails &&\n Math.abs(Date.now() - (this.last_request_time as number)) < this.fail_timeout\n );\n }\n\n /**\n * Check if the request timed out (network or http errors).\n * @param {RequestError} err\n * @return {boolean}\n */\n private _isRequestTimeout(err: RequestError): boolean {\n const code = err?.response?.statusCode;\n return (\n err.code === 'ETIMEDOUT' ||\n err.code === 'ESOCKETTIMEDOUT' ||\n err.code === 'ECONNRESET' ||\n code === HTTP_STATUS.REQUEST_TIMEOUT ||\n code === HTTP_STATUS.BAD_GATEWAY ||\n code === HTTP_STATUS.SERVICE_UNAVAILABLE ||\n code === HTTP_STATUS.GATEWAY_TIMEOUT\n );\n }\n\n /**\n * Set up a proxy.\n * @param {*} hostname\n * @param {*} config\n * @param {*} mainconfig\n * @param {*} isHTTPS\n */\n private _setupProxy(\n hostname: string,\n config: UpLinkConfLocal,\n mainconfig: Config,\n isHTTPS: boolean\n ): void {\n let noProxyList;\n const proxy_key: string = isHTTPS ? 'https_proxy' : 'http_proxy';\n debug('looking for %o', proxy_key);\n\n // get http_proxy and no_proxy configs\n if (proxy_key in config) {\n this.proxy = config[proxy_key];\n debug('found %o in uplink config', this.proxy);\n } else if (proxy_key in mainconfig) {\n this.proxy = mainconfig[proxy_key];\n debug('found %o in main config', this.proxy);\n }\n if ('no_proxy' in config) {\n noProxyList = config.no_proxy;\n } else if ('no_proxy' in mainconfig) {\n noProxyList = mainconfig.no_proxy;\n }\n\n // use wget-like algorithm to determine if proxy shouldn't be used\n if (hostname[0] !== '.') {\n hostname = '.' + hostname;\n }\n\n if (typeof noProxyList === 'string' && noProxyList.length) {\n noProxyList = noProxyList.split(',');\n }\n\n if (Array.isArray(noProxyList)) {\n for (let i = 0; i < noProxyList.length; i++) {\n let noProxyItem = noProxyList[i];\n if (noProxyItem[0] !== '.') {\n noProxyItem = '.' + noProxyItem;\n }\n if (hostname.endsWith(noProxyItem)) {\n if (this.proxy) {\n debug('not using proxy, excluded by @{rule}', noProxyItem);\n this.logger.debug(\n { url: this.url.href, rule: noProxyItem },\n 'not using proxy for @{url}, excluded by @{rule} rule'\n );\n this.proxy = undefined;\n }\n break;\n }\n }\n }\n\n if (typeof this.proxy === 'string') {\n debug('using proxy @{proxy} for @{url}', this.proxy, this.url.href);\n this.logger.debug(\n { url: this.url.href, proxy: this.proxy },\n 'using proxy @{proxy} for @{url}'\n );\n }\n }\n}\n\nexport { ProxyStorage };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/proxy",
3
- "version": "9.0.0-next-9.7",
3
+ "version": "9.0.0-next-9.9",
4
4
  "description": "Verdaccio Proxy Fetcher",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -33,17 +33,18 @@
33
33
  "node": ">=24"
34
34
  },
35
35
  "dependencies": {
36
- "@verdaccio/config": "9.0.0-next-9.7",
37
- "@verdaccio/core": "9.0.0-next-9.7",
38
- "JSONStream": "1.3.5",
36
+ "@verdaccio/config": "9.0.0-next-9.9",
37
+ "@verdaccio/core": "9.0.0-next-9.9",
39
38
  "debug": "4.4.3",
40
39
  "got": "14.6.6",
41
40
  "hpagent": "1.2.0",
42
- "lodash": "4.17.23"
41
+ "JSONStream": "1.3.5",
42
+ "lodash-es": "4.17.23"
43
43
  },
44
44
  "devDependencies": {
45
- "@verdaccio/logger": "9.0.0-next-9.7",
45
+ "@verdaccio/logger": "9.0.0-next-9.9",
46
46
  "@verdaccio/types": "14.0.0-next-9.4",
47
+ "@types/lodash-es": "4.17.12",
47
48
  "get-stream": "6.0.1",
48
49
  "nock": "13.5.6",
49
50
  "vitest": "4.1.0"