mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-04-08 02:54:13 -05:00
fix(proxy): validate protocol of proxy settings (#5125)
* fix(proxy): validate protocol of proxy settings * Update docs
This commit is contained in:
parent
83dbde5154
commit
13e0fdef08
7 changed files with 122 additions and 4 deletions
.changeset
packages/proxy
website
6
.changeset/funny-fireants-tan.md
Normal file
6
.changeset/funny-fireants-tan.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@verdaccio/proxy': patch
|
||||
'@verdaccio/website': patch
|
||||
---
|
||||
|
||||
fix(proxy): validate protocol of proxy settings
|
|
@ -578,12 +578,15 @@ class ProxyStorage implements IProxy {
|
|||
): void {
|
||||
let noProxyList;
|
||||
const proxy_key: string = isHTTPS ? 'https_proxy' : 'http_proxy';
|
||||
debug('looking for %o', proxy_key);
|
||||
|
||||
// get http_proxy and no_proxy configs
|
||||
if (proxy_key in config) {
|
||||
this.proxy = config[proxy_key];
|
||||
debug('found %o in uplink config', this.proxy);
|
||||
} else if (proxy_key in mainconfig) {
|
||||
this.proxy = mainconfig[proxy_key];
|
||||
debug('found %o in main config', this.proxy);
|
||||
}
|
||||
if ('no_proxy' in config) {
|
||||
noProxyList = config.no_proxy;
|
||||
|
@ -608,6 +611,7 @@ class ProxyStorage implements IProxy {
|
|||
}
|
||||
if (hostname.endsWith(noProxyItem)) {
|
||||
if (this.proxy) {
|
||||
debug('not using proxy, excluded by @{rule}', noProxyItem);
|
||||
this.logger.debug(
|
||||
{ url: this.url.href, rule: noProxyItem },
|
||||
'not using proxy for @{url}, excluded by @{rule} rule'
|
||||
|
@ -619,7 +623,22 @@ class ProxyStorage implements IProxy {
|
|||
}
|
||||
}
|
||||
|
||||
// validate proxy protocol matches the proxy_key type
|
||||
if (this.proxy) {
|
||||
const proxyUrl = new URL(this.proxy);
|
||||
const expectedProtocol = isHTTPS ? 'https:' : 'http:';
|
||||
if (proxyUrl.protocol !== expectedProtocol) {
|
||||
this.logger.error(
|
||||
{ proxy: this.proxy, expectedProtocol },
|
||||
`invalid protocol for ${proxy_key} - must be ${expectedProtocol}`
|
||||
);
|
||||
this.proxy = undefined;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.proxy === 'string') {
|
||||
debug('using proxy @{proxy} for @{url}', this.proxy, this.url.href);
|
||||
this.logger.debug(
|
||||
{ url: this.url.href, proxy: this.proxy },
|
||||
'using proxy @{proxy} for @{url}'
|
||||
|
|
87
packages/proxy/test/proxy.protocol.spec.ts
Normal file
87
packages/proxy/test/proxy.protocol.spec.ts
Normal file
|
@ -0,0 +1,87 @@
|
|||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import { Logger } from '@verdaccio/types';
|
||||
|
||||
import { ProxyStorage } from '../src';
|
||||
|
||||
const mockDebug = vi.fn();
|
||||
const mockInfo = vi.fn();
|
||||
const mockHttp = vi.fn();
|
||||
const mockError = vi.fn();
|
||||
const mockWarn = vi.fn();
|
||||
|
||||
const logger = {
|
||||
debug: mockDebug,
|
||||
info: mockInfo,
|
||||
http: mockHttp,
|
||||
error: mockError,
|
||||
warn: mockWarn,
|
||||
} as unknown as Logger;
|
||||
|
||||
function getProxyInstance(host, uplinkConf, appConfig) {
|
||||
uplinkConf.url = host;
|
||||
|
||||
return new ProxyStorage(uplinkConf, appConfig, logger);
|
||||
}
|
||||
|
||||
describe('Check protocol of proxy', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
test('validate main config protocol - http', () => {
|
||||
expect(
|
||||
getProxyInstance(
|
||||
'http://registry.domain.org',
|
||||
{ http_proxy: 'http://registry.local.org' },
|
||||
{}
|
||||
).proxy
|
||||
).toEqual('http://registry.local.org');
|
||||
});
|
||||
test('main config invalid protocol - http', () => {
|
||||
expect(
|
||||
getProxyInstance(
|
||||
'http://registry.domain.org',
|
||||
{ http_proxy: 'https://registry.local.org' },
|
||||
{}
|
||||
).proxy
|
||||
).toEqual(undefined);
|
||||
expect(mockError).toHaveBeenCalledOnce();
|
||||
});
|
||||
test('main config invalid protocol - https', () => {
|
||||
expect(
|
||||
getProxyInstance(
|
||||
'https://registry.domain.org',
|
||||
{ https_proxy: 'http://registry.local.org' },
|
||||
{}
|
||||
).proxy
|
||||
).toEqual(undefined);
|
||||
expect(mockError).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test('validate uplink config protocol - http', () => {
|
||||
expect(
|
||||
getProxyInstance(
|
||||
'https://registry.domain.org',
|
||||
{},
|
||||
{ https_proxy: 'https://proxy.domain.org' }
|
||||
).proxy
|
||||
).toEqual('https://proxy.domain.org');
|
||||
});
|
||||
test('uplink config invalid protocol - http', () => {
|
||||
expect(
|
||||
getProxyInstance('http://registry.domain.org', {}, { http_proxy: 'https://proxy.domain.org' })
|
||||
.proxy
|
||||
).toEqual(undefined);
|
||||
expect(mockError).toHaveBeenCalledOnce();
|
||||
});
|
||||
test('uplink config invalid protocol - https', () => {
|
||||
expect(
|
||||
getProxyInstance(
|
||||
'https://registry.domain.org',
|
||||
{},
|
||||
{ https_proxy: 'http://proxy.domain.org' }
|
||||
).proxy
|
||||
).toEqual(undefined);
|
||||
expect(mockError).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
|
@ -190,6 +190,8 @@ publish:
|
|||
allow_offline: false
|
||||
```
|
||||
|
||||
<small>Since: `verdaccio@2.3.6` due [#223](https://github.com/verdaccio/verdaccio/pull/223)</small>
|
||||
|
||||
### Checking Package Ownership {#check-owner}
|
||||
|
||||
By default, [package access](packages.md) defines who is allowed to publish and unpublish packages. By setting `check_owners` to _true_, only package owners are allowed to make changes to a package. The first owner of a package is the user who published the first version. Further owners can be added or removed using [`npm owner`](https://docs.npmjs.com/cli/v10/commands/npm-owner). You can find the list of current owners using `npm owner list` or by checking the package manifest under `maintainers`.
|
||||
|
@ -208,8 +210,6 @@ publish:
|
|||
keep_readmes: 'tagged'
|
||||
```
|
||||
|
||||
<small>Since: `verdaccio@2.3.6` due [#223](https://github.com/verdaccio/verdaccio/pull/223)</small>
|
||||
|
||||
### URL Prefix {#url-prefix}
|
||||
|
||||
The prefix is intended to be used when the server runs behinds the proxy and won't work properly if is used without a reverse proxy, check the **reverse proxy setup** page for more details.
|
||||
|
@ -307,7 +307,7 @@ https:
|
|||
|
||||
### Proxy {#proxy}
|
||||
|
||||
Proxies are special-purpose HTTP servers designed to transfer data from remote servers to local clients.
|
||||
Proxies are special-purpose HTTP servers designed to transfer data from remote servers to local clients. You can define a HTTP or HTTPS proxy in the main configuration or separately for each uplink. The definition for uplinks have higher priority. The proxy protocol (http or https) has to match the protocol of the registry or uplink URLs.
|
||||
|
||||
#### http_proxy and https_proxy {#http_proxy-and-https_proxy}
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ You can define mutiple uplinks and each of them must have an unique name (key).
|
|||
| maxage | string | No | 10m | all | the time threshold to the cache is valid | 2m |
|
||||
| fail_timeout | string | No | 10m | all | defines max time when a request becomes a failure | 5m |
|
||||
| max_fails | number | No | 2 | all | limit maximun failure request | 2 |
|
||||
| http_proxy | string | No | http://proxy.server.org | all | define HTTP proxy for registry access | No default |
|
||||
| https_proxy | string | No | https://proxy.server.org | all | define HTTPS proxy for registry access | No default |
|
||||
| no_proxy | string | No | localhost,127.0.0.1 | all | comma-separated list of hosts that should not use proxy | No default |
|
||||
| cache | boolean | No | [true,false] | >= 2.1 | cache all remote tarballs in storage | true |
|
||||
| auth | list | No | [see below](uplinks.md#auth-property) | >= 2.5 | assigns the header 'Authorization' [more info](http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules) | disabled |
|
||||
| headers | list | No | authorization: "Bearer SecretJWToken==" | all | list of custom headers for the uplink | disabled |
|
||||
|
|
|
@ -315,7 +315,7 @@ https:
|
|||
|
||||
### Proxy {#proxy}
|
||||
|
||||
Proxies are special-purpose HTTP servers designed to transfer data from remote servers to local clients.
|
||||
Proxies are special-purpose HTTP servers designed to transfer data from remote servers to local clients. You can define a HTTP or HTTPS proxy in the main configuration or separately for each uplink. The definition for uplinks have higher priority. The proxy protocol (http or https) has to match the protocol of the registry URL.
|
||||
|
||||
#### http_proxy and https_proxy {#http_proxy-and-https_proxy}
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@ You can define mutiple uplinks and each of them must have an unique name (key).
|
|||
| maxage | string | No | 10m | all | the time threshold to the cache is valid | 2m |
|
||||
| fail_timeout | string | No | 10m | all | defines max time when a request becomes a failure | 5m |
|
||||
| max_fails | number | No | 2 | all | limit maximun failure request | 2 |
|
||||
| http_proxy | string | No | http://proxy.server.org | all | define HTTP proxy for registry access | No default |
|
||||
| https_proxy | string | No | https://proxy.server.org | all | define HTTPS proxy for registry access | No default |
|
||||
| no_proxy | string | No | localhost,127.0.0.1 | all | comma-separated list of hosts that should not use proxy | No default |
|
||||
| cache | boolean | No | [true,false] | >= 2.1 | cache all remote tarballs in storage | true |
|
||||
| auth | list | No | [see below](uplinks.md#auth-property) | >= 2.5 | assigns the header 'Authorization' [more info](http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules) | disabled |
|
||||
| headers | list | No | authorization: "Bearer SecretJWToken==" | all | list of custom headers for the uplink | disabled |
|
||||
|
|
Loading…
Add table
Reference in a new issue