0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-01-27 22:59:51 -05:00
verdaccio/test/unit/modules/uplinks/up-storage.spec.ts
Juan Picado e939ca24af
feat: upgrade plugin htpassw major (#3712)
Replaces default auth plugin verdaccio-htpasswd@10.x by verdaccio-htpasswd@11.x which is being used in verdaccio 6.x (almost identical)
Apply backward compabiity
Reduces maintenance (monorepo plugin can be removed)
One more step to switch v6.x
Add Node.js 12 GH Action for check backward compatibility
2023-04-22 11:08:59 +02:00

461 lines
14 KiB
TypeScript

import _ from 'lodash';
import nock from 'nock';
import { Config, UpLinkConf } from '@verdaccio/types';
import AppConfig from '../../../../src/lib/config';
import {
API_ERROR,
ERROR_CODE,
HTTP_STATUS,
TOKEN_BASIC,
TOKEN_BEARER,
} from '../../../../src/lib/constants';
import { setup } from '../../../../src/lib/logger';
import ProxyStorage from '../../../../src/lib/up-storage';
import { DOMAIN_SERVERS } from '../../../functional/config.functional';
import { mockServer } from '../../__helper/mock';
import configExample from '../../partials/config';
setup({});
describe('UpStorage', () => {
const mockServerPort = 55547;
let mockRegistry;
const uplinkDefault = {
url: `http://localhost:${mockServerPort}`,
};
const generateProxy = (config: UpLinkConf = uplinkDefault) => {
const appConfig: Config = new AppConfig(configExample());
return new ProxyStorage(config, appConfig);
};
beforeAll(async () => {
mockRegistry = await mockServer(mockServerPort).init();
});
beforeEach(() => {
nock.cleanAll();
});
afterAll(function (done) {
mockRegistry[0].stop();
done();
});
test('should be defined', () => {
const proxy = generateProxy();
expect(proxy).toBeDefined();
});
describe('getRemoteMetadata', () => {
beforeEach(() => {
// @ts-ignore
process.env.TOKEN_TEST_ENV = 'foo';
// @ts-ignore
process.env.NPM_TOKEN = 'foo';
});
afterEach(() => {
delete process.env.TOKEN_TEST_ENV;
delete process.env.NPM_TOKEN;
});
test('should be get remote metadata', (done) => {
const proxy = generateProxy();
proxy.getRemoteMetadata('jquery', {}, (err, data, etag) => {
expect(err).toBeNull();
expect(_.isString(etag)).toBeTruthy();
expect(data.name).toBe('jquery');
done();
});
});
test('should handle 404 on be get remote metadata', (done) => {
nock('http://localhost:55547').get(`/jquery`).once().reply(404, { name: 'jquery' });
const proxy = generateProxy();
proxy.getRemoteMetadata('jquery', {}, (err) => {
expect(err).not.toBeNull();
expect(err.message).toMatch(/package does not exist on uplink/);
done();
});
});
test('should handle 500 on be get remote metadata', (done) => {
nock('http://localhost:55547').get(`/jquery`).once().reply(500, { name: 'jquery' });
const proxy = generateProxy();
proxy.getRemoteMetadata('jquery', {}, (err) => {
expect(err).not.toBeNull();
expect(err.message).toMatch(/bad status code: 500/);
done();
});
});
test('should be get remote metadata with etag', (done) => {
const proxy = generateProxy();
proxy.getRemoteMetadata('jquery', { etag: '123456' }, (err, data, etag) => {
expect(err).toBeNull();
expect(_.isString(etag)).toBeTruthy();
expect(data.name).toBe('jquery');
done();
});
});
test('should be get remote metadata package does not exist', (done) => {
const proxy = generateProxy();
proxy.getRemoteMetadata('@verdaccio/fake-package', { etag: '123456' }, (err) => {
expect(err).not.toBeNull();
expect(err.statusCode).toBe(HTTP_STATUS.NOT_FOUND);
expect(err.message).toMatch(API_ERROR.NOT_PACKAGE_UPLINK);
done();
});
});
test('should be get remote metadata with json when uplink is npmmirror', (done) => {
nock('https://registry.npmmirror.com').get(`/jquery`).reply(200, { name: 'jquery' });
const proxy = generateProxy({ url: 'https://registry.npmmirror.com' });
proxy.getRemoteMetadata('jquery', { json: true }, (err, data) => {
expect(err).toBeNull();
expect(data.name).toBe('jquery');
done();
});
});
test('should be get remote metadata with auth header bearer', (done) => {
nock('https://registry.npmmirror.com', {
reqheaders: {
authorization: 'Bearer foo',
},
})
.get(`/jquery`)
.reply(200, { name: 'jquery' });
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
type: TOKEN_BEARER,
token: 'foo',
},
});
proxy.getRemoteMetadata('jquery', {}, (err, data, etag) => {
expect(err).toBeNull();
// expect(_.isString(etag)).toBeTruthy();
expect(data.name).toBe('jquery');
done();
});
});
test('should be get remote metadata with auth node env TOKEN_TEST_ENV header bearer', (done) => {
nock('https://registry.npmmirror.com', {
reqheaders: {
authorization: 'Bearer foo',
},
})
.get(`/jquery`)
.reply(200, { name: 'jquery' });
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
type: TOKEN_BEARER,
token_env: 'TOKEN_TEST_ENV',
},
});
proxy.getRemoteMetadata('jquery', {}, (err, data, etag) => {
expect(err).toBeNull();
expect(data.name).toBe('jquery');
done();
});
});
test('should be get remote metadata with auth node env NPM_TOKEN header bearer', (done) => {
nock('https://registry.npmmirror.com', {
reqheaders: {
authorization: 'Bearer foo',
},
})
.get(`/jquery`)
.reply(200, { name: 'jquery' });
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
type: TOKEN_BEARER,
token_env: true,
},
});
proxy.getRemoteMetadata('jquery', {}, (err, data, etag) => {
expect(err).toBeNull();
expect(data.name).toBe('jquery');
done();
});
});
test('should be get remote metadata with auth header basic', (done) => {
nock('https://registry.npmmirror.com', {
reqheaders: {
authorization: 'Basic foo',
},
})
.get(`/jquery`)
.reply(200, { name: 'jquery' });
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
type: TOKEN_BASIC,
token: 'foo',
},
});
proxy.getRemoteMetadata('jquery', {}, (err, data, etag) => {
expect(err).toBeNull();
// expect(_.isString(etag)).toBeTruthy();
expect(data.name).toBe('jquery');
done();
});
});
});
describe('error handling', () => {
test('should fails if auth type is missing', () => {
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
type: TOKEN_BASIC,
token: undefined,
},
});
expect(function () {
proxy.getRemoteMetadata('jquery', {}, () => {});
}).toThrow(/token is required/);
});
test('should fails if token_env is undefined', () => {
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
type: TOKEN_BASIC,
token_env: undefined,
},
});
expect(function () {
proxy.getRemoteMetadata('jquery', {}, () => {});
}).toThrow(ERROR_CODE.token_required);
});
test('should fails if token_env is false', () => {
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
type: TOKEN_BASIC,
token_env: false,
},
});
expect(function () {
proxy.getRemoteMetadata('jquery', {}, () => {});
}).toThrow(ERROR_CODE.token_required);
});
test.skip('should fails if invalid token type', () => {
const proxy = generateProxy({
url: 'https://registry.npmmirror.com',
auth: {
token: 'SomethingWrong',
},
});
expect(function () {
proxy.getRemoteMetadata('jquery', {}, () => {});
}).toThrow(ERROR_CODE.token_required);
});
});
describe('fetchTarball', () => {
test.skip('should fetch a tarball from uplink', (done) => {
const proxy = generateProxy();
const tarball = `http://${DOMAIN_SERVERS}:${mockServerPort}/jquery/-/jquery-1.5.1.tgz`;
const stream = proxy.fetchTarball(tarball);
stream.on('error', function (err) {
expect(err).toBeNull();
done();
});
stream.on('content-length', function (contentLength) {
expect(contentLength).toBeDefined();
done();
});
});
test('should throw a 404 on fetch a tarball from uplink', (done) => {
const proxy = generateProxy();
const tarball = `http://${DOMAIN_SERVERS}:${mockServerPort}/jquery/-/no-exist-1.5.1.tgz`;
const stream = proxy.fetchTarball(tarball);
stream.on('error', function (err: any) {
expect(err).not.toBeNull();
expect(err.statusCode).toBe(HTTP_STATUS.NOT_FOUND);
expect(err.message).toMatch(API_ERROR.NOT_FILE_UPLINK);
done();
});
stream.on('content-length', function (contentLength) {
expect(contentLength).toBeDefined();
done();
});
});
test('should be offline uplink', (done) => {
const proxy = generateProxy();
const tarball = 'http://404.verdaccioo.com';
const stream = proxy.fetchTarball(tarball);
expect(proxy.failed_requests).toBe(0);
// to test a uplink is offline we have to be try 3 times
// the default failed request are set to 2
process.nextTick(function () {
stream.on('error', function (err) {
expect(err).not.toBeNull();
// expect(err.statusCode).toBe(404);
expect(proxy.failed_requests).toBe(1);
const streamSecondTry = proxy.fetchTarball(tarball);
streamSecondTry.on('error', function (err) {
expect(err).not.toBeNull();
/*
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
*/
// expect(err.statusCode).toBe(404);
expect(proxy.failed_requests).toBe(2);
const streamThirdTry = proxy.fetchTarball(tarball);
streamThirdTry.on('error', function (err: any) {
expect(err).not.toBeNull();
expect(err.statusCode).toBe(HTTP_STATUS.INTERNAL_ERROR);
expect(proxy.failed_requests).toBe(2);
expect(err.message).toMatch(API_ERROR.UPLINK_OFFLINE);
done();
});
});
});
});
}, 10000);
});
describe('isUplinkValid', () => {
describe('valid use cases', () => {
const validateUpLink = (
url: string,
tarBallUrl = `${url}/artifactory/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz`
) => {
const uplinkConf = { url };
const proxy: any = generateProxy(uplinkConf);
return proxy.isUplinkValid(tarBallUrl);
};
test('should validate tarball path against uplink', () => {
expect(validateUpLink('https://artifactory.mydomain.com')).toBe(true);
});
test('should validate tarball path against uplink case#2', () => {
expect(validateUpLink('https://artifactory.mydomain.com:443')).toBe(true);
});
test('should validate tarball path against uplink case#3', () => {
expect(validateUpLink('http://localhost')).toBe(true);
});
test('should validate tarball path against uplink case#4', () => {
expect(validateUpLink('http://my.domain.test')).toBe(true);
});
test('should validate tarball path against uplink case#5', () => {
expect(validateUpLink('http://my.domain.test:3000')).toBe(true);
});
// corner case https://github.com/verdaccio/verdaccio/issues/571
test('should validate tarball path against uplink case#6', () => {
// same protocol, same domain, port === 443 which is also the standard for https
expect(
validateUpLink(
'https://my.domain.test',
`https://my.domain.test:443/artifactory/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz`
)
).toBe(true);
});
test('should validate tarball path against uplink case#7', () => {
expect(validateUpLink('https://artifactory.mydomain.com:5569')).toBe(true);
});
test('should validate tarball path against uplink case#8', () => {
expect(validateUpLink('https://localhost:5539')).toBe(true);
});
});
describe('invalid use cases', () => {
test('should fails on validate tarball path against uplink', () => {
const url = 'https://artifactory.mydomain.com';
const tarBallUrl = 'https://localhost/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
const uplinkConf = { url };
const proxy: any = generateProxy(uplinkConf);
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
});
test('should fails on validate tarball path against uplink case#2', () => {
// different domain same, same port, same protocol
const url = 'https://domain';
const tarBallUrl = 'https://localhost/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
const uplinkConf = { url };
const proxy: any = generateProxy(uplinkConf);
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
});
test('should fails on validate tarball path against uplink case#3', () => {
// same domain, different protocol, different port
const url = 'http://localhost:5001';
const tarBallUrl = 'https://localhost:4000/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
const uplinkConf = { url };
const proxy: any = generateProxy(uplinkConf);
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
});
test('should fails on validate tarball path against uplink case#4', () => {
// same domain, same protocol, different port
const url = 'https://subdomain.domain:5001';
const tarBallUrl =
'https://subdomain.domain:4000/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
const uplinkConf = { url };
const proxy: any = generateProxy(uplinkConf);
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
});
test('should fails on validate tarball path against uplink case#5', () => {
// different protocol, different domain, different port
const url = 'https://subdomain.my:5001';
const tarBallUrl = 'http://subdomain.domain:4000/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz';
const uplinkConf = { url };
const proxy: any = generateProxy(uplinkConf);
expect(proxy.isUplinkValid(tarBallUrl)).toBe(false);
});
});
});
});