0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-30 22:34:10 -05:00

refactor: pass options instead request object (#2605)

This commit is contained in:
Juan Picado 2021-10-29 09:00:02 +02:00 committed by GitHub
parent 1322ffc2c4
commit 16458f801e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 163 additions and 40 deletions

View file

@ -40,7 +40,7 @@ export default function (route: Router, auth: IAuth, storage: Storage, config: C
route.get( route.get(
'/:package/:version?', '/:package/:version?',
can('access'), can('access'),
function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { function (req: $RequestExtend, _res: $ResponseExtend, next: $NextFunctionVer): void {
debug('init package by version'); debug('init package by version');
const name = req.params.package; const name = req.params.package;
const getPackageMetaCallback = function (err, metadata: Package): void { const getPackageMetaCallback = function (err, metadata: Package): void {
@ -49,7 +49,11 @@ export default function (route: Router, auth: IAuth, storage: Storage, config: C
return next(err); return next(err);
} }
debug('convert dist remote to local with prefix %o', config?.url_prefix); debug('convert dist remote to local with prefix %o', config?.url_prefix);
metadata = convertDistRemoteToLocalTarballUrls(metadata, req, config?.url_prefix); metadata = convertDistRemoteToLocalTarballUrls(
metadata,
{ protocol: req.protocol, headers: req.headers as any, host: req.host },
config?.url_prefix
);
let queryVersion = req.params.version; let queryVersion = req.params.version;
debug('query by param version: %o', queryVersion); debug('query by param version: %o', queryVersion);

View file

@ -41,7 +41,6 @@
}, },
"devDependencies": { "devDependencies": {
"@verdaccio/types": "workspace:11.0.0-6-next.9", "@verdaccio/types": "workspace:11.0.0-6-next.9",
"express": "4.17.1",
"node-mocks-http": "1.10.1" "node-mocks-http": "1.10.1"
}, },
"scripts": { "scripts": {

View file

@ -1,5 +1,5 @@
import { Package } from '@verdaccio/types'; import { Package } from '@verdaccio/types';
import { Request } from 'express'; import { RequestOptions } from '@verdaccio/url';
import _ from 'lodash'; import _ from 'lodash';
import { getLocalRegistryTarballUri } from './getLocalRegistryTarballUri'; import { getLocalRegistryTarballUri } from './getLocalRegistryTarballUri';
@ -13,7 +13,7 @@ import { getLocalRegistryTarballUri } from './getLocalRegistryTarballUri';
*/ */
export function convertDistRemoteToLocalTarballUrls( export function convertDistRemoteToLocalTarballUrls(
pkg: Package, pkg: Package,
req: Request, request: RequestOptions,
urlPrefix: string | void urlPrefix: string | void
): Package { ): Package {
for (const ver in pkg.versions) { for (const ver in pkg.versions) {
@ -21,7 +21,12 @@ export function convertDistRemoteToLocalTarballUrls(
const distName = pkg.versions[ver].dist; const distName = pkg.versions[ver].dist;
if (_.isNull(distName) === false && _.isNull(distName.tarball) === false) { if (_.isNull(distName) === false && _.isNull(distName.tarball) === false) {
distName.tarball = getLocalRegistryTarballUri(distName.tarball, pkg.name, req, urlPrefix); distName.tarball = getLocalRegistryTarballUri(
distName.tarball,
pkg.name,
request,
urlPrefix
);
} }
} }
} }

View file

@ -1,12 +1,12 @@
import URL from 'url'; import URL from 'url';
import { Request } from 'express'; import { RequestOptions } from '@verdaccio/url';
import buildDebug from 'debug'; import buildDebug from 'debug';
import { getPublicUrl } from '@verdaccio/url'; import { getPublicUrl } from '@verdaccio/url';
const debug = buildDebug('verdaccio:core:url'); const debug = buildDebug('verdaccio:core:url');
function extractTarballFromUrl(url: string): string { export function extractTarballFromUrl(url: string): string {
// @ts-ignore // @ts-ignore
return URL.parse(url).pathname.replace(/^.*\//, ''); return URL.parse(url).pathname.replace(/^.*\//, '');
} }
@ -18,10 +18,10 @@ function extractTarballFromUrl(url: string): string {
export function getLocalRegistryTarballUri( export function getLocalRegistryTarballUri(
uri: string, uri: string,
pkgName: string, pkgName: string,
req: Request, requestOptions: RequestOptions,
urlPrefix: string | void urlPrefix: string | void
): string { ): string {
const currentHost = req.headers.host; const currentHost = requestOptions?.headers?.host;
if (!currentHost) { if (!currentHost) {
return uri; return uri;
@ -29,7 +29,7 @@ export function getLocalRegistryTarballUri(
const tarballName = extractTarballFromUrl(uri); const tarballName = extractTarballFromUrl(uri);
debug('tarball name %o', tarballName); debug('tarball name %o', tarballName);
// header only set with proxy that setup with HTTPS // header only set with proxy that setup with HTTPS
const domainRegistry = getPublicUrl(urlPrefix || '', req); const domainRegistry = getPublicUrl(urlPrefix || '', requestOptions);
return `${domainRegistry}${pkgName}/-/${tarballName}`; return `${domainRegistry}${pkgName}/-/${tarballName}`;
} }

View file

@ -30,7 +30,11 @@ describe('convertDistRemoteToLocalTarballUrls', () => {
}, },
url: '/', url: '/',
}); });
const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), req); const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
});
expect(convertDist.versions['1.0.0'].dist.tarball).toEqual(buildURI(fakeHost, '1.0.0')); expect(convertDist.versions['1.0.0'].dist.tarball).toEqual(buildURI(fakeHost, '1.0.0'));
expect(convertDist.versions['1.0.1'].dist.tarball).toEqual(buildURI(fakeHost, '1.0.1')); expect(convertDist.versions['1.0.1'].dist.tarball).toEqual(buildURI(fakeHost, '1.0.1'));
}); });
@ -43,7 +47,11 @@ describe('convertDistRemoteToLocalTarballUrls', () => {
}, },
url: '/', url: '/',
}); });
const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), req); const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
});
expect(convertDist.versions['1.0.0'].dist.tarball).toEqual( expect(convertDist.versions['1.0.0'].dist.tarball).toEqual(
convertDist.versions['1.0.0'].dist.tarball convertDist.versions['1.0.0'].dist.tarball
); );
@ -57,7 +65,11 @@ describe('convertDistRemoteToLocalTarballUrls', () => {
}, },
url: '/', url: '/',
}); });
const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), req); const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
});
expect(convertDist.versions['1.0.0'].dist.tarball).toEqual( expect(convertDist.versions['1.0.0'].dist.tarball).toEqual(
convertDist.versions['1.0.0'].dist.tarball convertDist.versions['1.0.0'].dist.tarball
); );

View file

@ -12,6 +12,9 @@
}, },
{ {
"path": "../url" "path": "../url"
},
{
"path": "../core"
} }
] ]
} }

View file

@ -88,18 +88,26 @@ export function validateURL(publicUrl: string | void) {
} }
} }
export function getPublicUrl(url_prefix: string = '', req): string { export type RequestOptions = {
host: string;
protocol: string;
headers: { [key: string]: string };
};
export function getPublicUrl(url_prefix: string = '', requestOptions: RequestOptions): string {
if (validateURL(process.env.VERDACCIO_PUBLIC_URL as string)) { if (validateURL(process.env.VERDACCIO_PUBLIC_URL as string)) {
const envURL = new URL(wrapPrefix(url_prefix), process.env.VERDACCIO_PUBLIC_URL as string).href; const envURL = new URL(wrapPrefix(url_prefix), process.env.VERDACCIO_PUBLIC_URL as string).href;
debug('public url by env %o', envURL); debug('public url by env %o', envURL);
return envURL; return envURL;
} else if (req.get('host')) { } else if (requestOptions.headers['host']) {
const host = req.get('host'); const host = requestOptions.headers['host'];
if (!isHost(host)) { if (!isHost(host)) {
throw new Error('invalid host'); throw new Error('invalid host');
} }
const protoHeader = process.env.VERDACCIO_FORWARDED_PROTO ?? HEADERS.FORWARDED_PROTO; const protoHeader =
const protocol = getWebProtocol(req.get(protoHeader), req.protocol); process.env.VERDACCIO_FORWARDED_PROTO?.toLocaleLowerCase() ??
HEADERS.FORWARDED_PROTO.toLowerCase();
const protocol = getWebProtocol(requestOptions.headers[protoHeader], requestOptions.protocol);
const combinedUrl = combineBaseUrl(protocol, host, url_prefix); const combinedUrl = combineBaseUrl(protocol, host, url_prefix);
debug('public url by request %o', combinedUrl); debug('public url by request %o', combinedUrl);
return combinedUrl; return combinedUrl;

View file

@ -11,7 +11,13 @@ describe('host', () => {
method: 'GET', method: 'GET',
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('/');
}); });
test('get a valid host', () => { test('get a valid host', () => {
@ -22,7 +28,13 @@ describe('host', () => {
}, },
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('http://some.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/');
}); });
test('check a valid host header injection', () => { test('check a valid host header injection', () => {
@ -31,11 +43,15 @@ describe('host', () => {
headers: { headers: {
host: `some.com"><svg onload="alert(1)">`, host: `some.com"><svg onload="alert(1)">`,
}, },
hostname: `some.com"><svg onload="alert(1)">`,
url: '/', url: '/',
}); });
expect(function () { expect(function () {
// @ts-expect-error getPublicUrl('', {
getPublicUrl({}, req); host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
});
}).toThrow('invalid host'); }).toThrow('invalid host');
}); });
@ -48,7 +64,13 @@ describe('host', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl('/prefix/', req)).toEqual('http://some.com/prefix/'); expect(
getPublicUrl('/prefix/', {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/prefix/');
}); });
test('get a valid host with prefix no trailing', () => { test('get a valid host with prefix no trailing', () => {
@ -60,7 +82,13 @@ describe('host', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl('/prefix-no-trailing', req)).toEqual('http://some.com/prefix-no-trailing/'); expect(
getPublicUrl('/prefix-no-trailing', {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/prefix-no-trailing/');
}); });
test('get a valid host with null prefix', () => { test('get a valid host with null prefix', () => {
@ -72,7 +100,13 @@ describe('host', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(null, req)).toEqual('http://some.com/'); expect(
getPublicUrl(null, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/');
}); });
}); });
@ -87,7 +121,13 @@ describe('X-Forwarded-Proto', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('https://some.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('https://some.com/');
}); });
test('with a invalid X-Forwarded-Proto https', () => { test('with a invalid X-Forwarded-Proto https', () => {
@ -100,7 +140,13 @@ describe('X-Forwarded-Proto', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('http://some.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/');
}); });
test('with a HAProxy X-Forwarded-Proto https', () => { test('with a HAProxy X-Forwarded-Proto https', () => {
@ -113,7 +159,13 @@ describe('X-Forwarded-Proto', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('https://some.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('https://some.com/');
}); });
test('with a HAProxy X-Forwarded-Proto different protocol', () => { test('with a HAProxy X-Forwarded-Proto different protocol', () => {
@ -126,7 +178,13 @@ describe('X-Forwarded-Proto', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('http://some.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/');
}); });
}); });
@ -142,7 +200,13 @@ describe('env variable', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('https://env.domain.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('https://env.domain.com/');
delete process.env.VERDACCIO_PUBLIC_URL; delete process.env.VERDACCIO_PUBLIC_URL;
}); });
@ -157,7 +221,13 @@ describe('env variable', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('https://env.domain.com/urlPrefix/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('https://env.domain.com/urlPrefix/');
delete process.env.VERDACCIO_PUBLIC_URL; delete process.env.VERDACCIO_PUBLIC_URL;
}); });
@ -172,7 +242,13 @@ describe('env variable', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('https://env.domain.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('https://env.domain.com/');
delete process.env.VERDACCIO_PUBLIC_URL; delete process.env.VERDACCIO_PUBLIC_URL;
}); });
@ -187,7 +263,13 @@ describe('env variable', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('http://some.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/');
delete process.env.VERDACCIO_PUBLIC_URL; delete process.env.VERDACCIO_PUBLIC_URL;
}); });
@ -202,7 +284,13 @@ describe('env variable', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('http://some.com/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some.com/');
delete process.env.VERDACCIO_PUBLIC_URL; delete process.env.VERDACCIO_PUBLIC_URL;
}); });
@ -217,7 +305,13 @@ describe('env variable', () => {
url: '/', url: '/',
}); });
expect(getPublicUrl(undefined, req)).toEqual('http://some/'); expect(
getPublicUrl(undefined, {
host: req.hostname,
headers: req.headers as any,
protocol: req.protocol,
})
).toEqual('http://some/');
delete process.env.VERDACCIO_PUBLIC_URL; delete process.env.VERDACCIO_PUBLIC_URL;
}); });
}); });

View file

@ -80,7 +80,7 @@ function addPackageWebApi(route: Router, storage: Storage, auth: IAuth, config:
pkgCopy.dist.tarball = getLocalRegistryTarballUri( pkgCopy.dist.tarball = getLocalRegistryTarballUri(
pkgCopy.dist.tarball, pkgCopy.dist.tarball,
pkg.name, pkg.name,
req, { protocol: req.protocol, headers: req.headers as any, host: req.hostname },
config?.url_prefix config?.url_prefix
); );
} }

View file

@ -42,7 +42,7 @@ function addSidebarWebApi(route: Router, config: Config, storage: Storage, auth:
let sideBarInfo = _.clone(info); let sideBarInfo = _.clone(info);
sideBarInfo.versions = convertDistRemoteToLocalTarballUrls( sideBarInfo.versions = convertDistRemoteToLocalTarballUrls(
info, info,
req, { protocol: req.protocol, headers: req.headers as any, host: req.hostname },
config.url_prefix config.url_prefix
).versions; ).versions;
if (typeof v === 'string' && isVersionValid(info, v)) { if (typeof v === 'string' && isVersionValid(info, v)) {

View file

@ -398,7 +398,6 @@ importers:
'@verdaccio/types': workspace:11.0.0-6-next.9 '@verdaccio/types': workspace:11.0.0-6-next.9
'@verdaccio/url': workspace:11.0.0-6-next.7 '@verdaccio/url': workspace:11.0.0-6-next.7
'@verdaccio/utils': workspace:6.0.0-6-next.8 '@verdaccio/utils': workspace:6.0.0-6-next.8
express: 4.17.1
lodash: 4.17.21 lodash: 4.17.21
node-mocks-http: 1.10.1 node-mocks-http: 1.10.1
dependencies: dependencies:
@ -408,7 +407,6 @@ importers:
lodash: 4.17.21 lodash: 4.17.21
devDependencies: devDependencies:
'@verdaccio/types': link:../types '@verdaccio/types': link:../types
express: 4.17.1
node-mocks-http: 1.10.1 node-mocks-http: 1.10.1
packages/core/types: packages/core/types: