0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-01-13 22:48:31 -05:00

chore: fix unpublish issues, fix unit test

This commit is contained in:
Juan Picado @jotadeveloper 2019-02-24 23:20:25 +01:00
parent cab3596843
commit 9e17d2bc27
No known key found for this signature in database
GPG key ID: 18AC54485952D158
30 changed files with 825 additions and 730 deletions

1
.gitignore vendored
View file

@ -6,6 +6,7 @@ build/
### Test ### Test
test/unit/partials/store/test-*-storage/* test/unit/partials/store/test-*-storage/*
test/unit/partials/store/storage_default_storage/*
.verdaccio-db.json .verdaccio-db.json
.sinopia-db.json .sinopia-db.json

View file

@ -86,10 +86,10 @@
"husky": "0.15.0-rc.8", "husky": "0.15.0-rc.8",
"identity-obj-proxy": "3.0.0", "identity-obj-proxy": "3.0.0",
"in-publish": "2.0.0", "in-publish": "2.0.0",
"jest": "23.6.0", "jest": "24.1.0",
"jest-environment-jsdom": "23.4.0", "jest-environment-jsdom": "24.0.0",
"jest-environment-jsdom-global": "1.1.0", "jest-environment-jsdom-global": "1.1.1",
"jest-environment-node": "23.4.0", "jest-environment-node": "24.0.0",
"lint-staged": "7.3.0", "lint-staged": "7.3.0",
"localstorage-memory": "1.0.2", "localstorage-memory": "1.0.2",
"mini-css-extract-plugin": "0.4.3", "mini-css-extract-plugin": "0.4.3",

View file

@ -24,7 +24,7 @@ export default function publish(router: Router, auth: IAuth, storage: IStorageHa
router.put('/:package/:_rev?/:revision?', can('publish'), media(mime.getType('json')), expectJson, publishPackage(storage, config)); router.put('/:package/:_rev?/:revision?', can('publish'), media(mime.getType('json')), expectJson, publishPackage(storage, config));
// un-publishing an entire package // un-publishing an entire package
router.delete('/:package/-rev/*', can('unpublish'), can('publish'), unPublishPackage(storage)); router.delete('/:package/-rev/*', can('unpublish'), unPublishPackage(storage));
// removing a tarball // removing a tarball
router.delete('/:package/-/:filename/-rev/:revision', can('unpublish'), can('publish'), removeTarball(storage)); router.delete('/:package/-/:filename/-rev/:revision', can('unpublish'), can('publish'), removeTarball(storage));

View file

@ -106,7 +106,7 @@ const defineAPI = function(config: IConfig, storage: IStorageHandler) {
export default (async function(configHash: any) { export default (async function(configHash: any) {
setup(configHash.logs); setup(configHash.logs);
const config: IConfig = new AppConfig(configHash); const config: IConfig = new AppConfig(_.cloneDeep(configHash));
const storage: IStorageHandler = new Storage(config); const storage: IStorageHandler = new Storage(config);
// waits until init calls have been initialized // waits until init calls have been initialized
await storage.init(config); await storage.init(config);

View file

@ -60,6 +60,19 @@ export function allow_action(action: string) {
}; };
} }
export function handleSpecialUnpublish() {
return function(user: RemoteUser, pkg: Package, callback: Callback) {
const action: string = 'unpublish';
const hasSupport: boolean = _.isNil(pkg[action]) === false ? pkg[action] : false;
if (hasSupport === false) {
return callback(null, undefined);
}
return allow_action(action)(user, pkg, callback);
};
}
export function getDefaultPlugins() { export function getDefaultPlugins() {
return { return {
authenticate(user: string, password: string, cb: Callback) { authenticate(user: string, password: string, cb: Callback) {
@ -72,7 +85,7 @@ export function getDefaultPlugins() {
allow_access: allow_action('access'), allow_access: allow_action('access'),
allow_publish: allow_action('publish'), allow_publish: allow_action('publish'),
allow_unpublish: allow_action('unpublish'), allow_unpublish: handleSpecialUnpublish(),
}; };
} }

View file

@ -191,32 +191,32 @@ class Auth implements IAuth {
} }
allow_unpublish({ packageName, packageVersion }: AuthPluginPackage, user: string, callback: Callback) { allow_unpublish({ packageName, packageVersion }: AuthPluginPackage, user: string, callback: Callback) {
const plugins = this.plugins.slice(0);
const self = this;
// $FlowFixMe // $FlowFixMe
const pkg = Object.assign({ name: packageName, version: packageVersion }, getMatchedPackagesSpec(packageName, this.config.packages)); const pkg = Object.assign({ name: packageName, version: packageVersion }, getMatchedPackagesSpec(packageName, this.config.packages));
this.logger.trace({ packageName }, 'allow unpublish for @{packageName}'); this.logger.trace({ packageName }, 'allow unpublish for @{packageName}');
(function next() { for (const plugin of this.plugins) {
const plugin = plugins.shift();
if (_.isFunction(plugin.allow_unpublish) === false) { if (_.isFunction(plugin.allow_unpublish) === false) {
return next(); continue;
} else {
plugin.allow_unpublish(user, pkg, (err, ok: boolean) => {
if (err) {
this.logger.trace({ packageName }, 'forbidden publish for @{packageName}, it will fallback on unpublish permissions');
return callback(err);
}
if (_.isNil(ok) === true) {
this.logger.trace({ packageName }, 'we bypass unpublish for @{packageName}, publish will handle the access');
return this.allow_publish(...arguments);
}
if (ok) {
this.logger.trace({ packageName }, 'allowed unpublish for @{packageName}');
return callback(null, ok);
}
});
} }
}
plugin.allow_unpublish(user, pkg, (err, ok: boolean) => {
if (err) {
self.logger.trace({ packageName }, 'forbidden unpublish for @{packageName}');
return callback(err);
}
if (ok) {
self.logger.trace({ packageName }, 'allowed unpublish for @{packageName}');
return callback(null, ok);
}
next(); // cb(null, false) causes next plugin to roll
});
})();
} }
/** /**

View file

@ -123,8 +123,9 @@ export function normalisePackageAccess(packages: PackageList): PackageList {
delete normalizedPkgs[pkg].allow_publish; delete normalizedPkgs[pkg].allow_publish;
normalizedPkgs[pkg].proxy = normalizeUserList(packages[pkg].proxy_access, packages[pkg].proxy); normalizedPkgs[pkg].proxy = normalizeUserList(packages[pkg].proxy_access, packages[pkg].proxy);
delete normalizedPkgs[pkg].proxy_access; delete normalizedPkgs[pkg].proxy_access;
// if unpublish is not defined, we set to false to fallback in publish access
// $FlowFixMe // $FlowFixMe
normalizedPkgs[pkg].unpublish = normalizeUserList([], packages[pkg].unpublish); normalizedPkgs[pkg].unpublish = _.isUndefined(packages[pkg].unpublish) ? false : normalizeUserList([], packages[pkg].unpublish);
} }
} }

View file

@ -16,7 +16,7 @@ exports[`Publish endpoints - publish package should add a new package 1`] = `
], ],
"results": Array [ "results": Array [
Object { Object {
"isThrow": false, "type": "return",
"value": undefined, "value": undefined,
}, },
], ],
@ -40,7 +40,7 @@ exports[`Publish endpoints - publish package should change the existing package
], ],
"results": Array [ "results": Array [
Object { Object {
"isThrow": false, "type": "return",
"value": undefined, "value": undefined,
}, },
], ],

View file

@ -14,7 +14,7 @@ exports[`Verdaccio update banner should print major update banner 1`] = `
], ],
"results": Array [ "results": Array [
Object { Object {
"isThrow": false, "type": "return",
"value": undefined, "value": undefined,
}, },
], ],
@ -35,7 +35,7 @@ exports[`Verdaccio update banner should print minor update banner 1`] = `
], ],
"results": Array [ "results": Array [
Object { Object {
"isThrow": false, "type": "return",
"value": undefined, "value": undefined,
}, },
], ],
@ -56,7 +56,7 @@ exports[`Verdaccio update banner should print patch update banner 1`] = `
], ],
"results": Array [ "results": Array [
Object { Object {
"isThrow": false, "type": "return",
"value": undefined, "value": undefined,
}, },
], ],
@ -75,7 +75,7 @@ exports[`Verdaccio update banner when default registry returns with error 1`] =
], ],
"results": Array [ "results": Array [
Object { Object {
"isThrow": false, "type": "return",
"value": undefined, "value": undefined,
}, },
], ],

View file

@ -5,7 +5,6 @@ import _ from 'lodash';
import path from 'path'; import path from 'path';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import Config from '../../../src/lib/config';
import endPointAPI from '../../../src/api/index'; import endPointAPI from '../../../src/api/index';
import {HEADERS, HTTP_STATUS, HEADER_TYPE} from '../../../src/lib/constants'; import {HEADERS, HTTP_STATUS, HEADER_TYPE} from '../../../src/lib/constants';
@ -27,7 +26,6 @@ const parseConfigurationJWTFile = () => {
const FORBIDDEN_VUE: string = 'authorization required to access package vue'; const FORBIDDEN_VUE: string = 'authorization required to access package vue';
describe('endpoint user auth JWT unit test', () => { describe('endpoint user auth JWT unit test', () => {
let config;
let app; let app;
let mockRegistry; let mockRegistry;
@ -36,21 +34,22 @@ describe('endpoint user auth JWT unit test', () => {
const mockServerPort = 55546; const mockServerPort = 55546;
rimraf(store, async () => { rimraf(store, async () => {
const confS = parseConfigFile(parseConfigurationJWTFile()); const confS = parseConfigFile(parseConfigurationJWTFile());
const configForTest = _.clone(confS); const configForTest = _.assign({}, _.cloneDeep(confS), {
configForTest.storage = store; storage: store,
configForTest.auth = { plinks: {
htpasswd: { npmjs: {
file: './test-jwt-storage/.htpasswd' url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
}
},
self_path: store,
auth: {
htpasswd: {
file: './test-jwt-storage/.htpasswd'
}
} }
}; });
configForTest.uplinks = {
npmjs: { app = await endPointAPI(configForTest);
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
}
};
configForTest.self_path = store;
config = new Config(configForTest);
app = await endPointAPI(config);
mockRegistry = await mockServer(mockServerPort).init(); mockRegistry = await mockServer(mockServerPort).init();
done(); done();
}); });

View file

@ -5,7 +5,6 @@ import rimraf from 'rimraf';
import { HEADERS, HTTP_STATUS } from '../../../src/lib/constants'; import { HEADERS, HTTP_STATUS } from '../../../src/lib/constants';
import configDefault from '../partials/config/config_access'; import configDefault from '../partials/config/config_access';
import Config from '../../../src/lib/config';
import endPointAPI from '../../../src/api/index'; import endPointAPI from '../../../src/api/index';
import {mockServer} from './mock'; import {mockServer} from './mock';
import {DOMAIN_SERVERS} from '../../functional/config.functional'; import {DOMAIN_SERVERS} from '../../functional/config.functional';
@ -13,7 +12,6 @@ import {DOMAIN_SERVERS} from '../../functional/config.functional';
require('../../../src/lib/logger').setup([]); require('../../../src/lib/logger').setup([]);
describe('api with no limited access configuration', () => { describe('api with no limited access configuration', () => {
let config;
let app; let app;
let mockRegistry; let mockRegistry;
@ -21,20 +19,21 @@ describe('api with no limited access configuration', () => {
const mockServerPort = 55530; const mockServerPort = 55530;
const store = path.join(__dirname, './partials/store/access-storage'); const store = path.join(__dirname, './partials/store/access-storage');
rimraf(store, async () => { rimraf(store, async () => {
const configForTest = _.clone(configDefault); const configForTest = _.assign({}, _.cloneDeep(configDefault), {
configForTest.auth = { auth: {
htpasswd: { htpasswd: {
file: './access-storage/htpasswd-access-test' file: './access-storage/htpasswd-access-test'
}
},
self_path: store,
uplinks: {
npmjs: {
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
}
} }
}; });
configForTest.self_path = store;
configForTest.uplinks = { app = await endPointAPI(configForTest);
npmjs: {
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
}
};
config = new Config(configForTest);
app = await endPointAPI(config);
mockRegistry = await mockServer(mockServerPort).init(); mockRegistry = await mockServer(mockServerPort).init();
done(); done();
}); });

View file

@ -5,7 +5,6 @@ import _ from 'lodash';
import path from 'path'; import path from 'path';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import Config from '../../../src/lib/config';
import endPointAPI from '../../../src/api/index'; import endPointAPI from '../../../src/api/index';
import {mockServer} from './mock'; import {mockServer} from './mock';
import {parseConfigFile} from '../../../src/lib/utils'; import {parseConfigFile} from '../../../src/lib/utils';
@ -22,7 +21,6 @@ const parseConfigurationProfile = () => {
describe('endpoint user profile', () => { describe('endpoint user profile', () => {
let config;
let app; let app;
let mockRegistry; let mockRegistry;
@ -31,16 +29,16 @@ describe('endpoint user profile', () => {
const mockServerPort = 55544; const mockServerPort = 55544;
rimraf(store, async () => { rimraf(store, async () => {
const parsedConfig = parseConfigFile(parseConfigurationProfile()); const parsedConfig = parseConfigFile(parseConfigurationProfile());
const configForTest = _.clone(parsedConfig); const configForTest = _.assign({}, _.cloneDeep(parsedConfig), {
configForTest.storage = store; storage: store,
configForTest.auth = { auth: {
htpasswd: { htpasswd: {
file: './test-profile-storage/.htpasswd' file: './test-profile-storage/.htpasswd'
} }
}; },
configForTest.self_path = store; self_path: store
config = new Config(configForTest); });
app = await endPointAPI(config); app = await endPointAPI(configForTest);
mockRegistry = await mockServer(mockServerPort).init(); mockRegistry = await mockServer(mockServerPort).init();
done(); done();
}); });

View file

@ -5,39 +5,40 @@ import rimraf from 'rimraf';
import configDefault from '../partials/config/index'; import configDefault from '../partials/config/index';
import publishMetadata from '../partials/publish-api'; import publishMetadata from '../partials/publish-api';
import Config from '../../../src/lib/config';
import endPointAPI from '../../../src/api/index'; import endPointAPI from '../../../src/api/index';
import { HEADERS, API_ERROR, HTTP_STATUS, HEADER_TYPE, API_MESSAGE} from '../../../src/lib/constants'; import {HEADERS, API_ERROR, HTTP_STATUS, HEADER_TYPE, API_MESSAGE, TOKEN_BEARER} from '../../../src/lib/constants';
import {mockServer} from './mock'; import {mockServer} from './mock';
import {DOMAIN_SERVERS} from '../../functional/config.functional'; import {DOMAIN_SERVERS} from '../../functional/config.functional';
import {buildToken} from '../../../src/lib/utils';
require('../../../src/lib/logger').setup([]); require('../../../src/lib/logger').setup([]);
const credentials = { name: 'jota', password: 'secretPass' }; const credentials = { name: 'jota', password: 'secretPass' };
describe('endpoint unit test', () => { describe('endpoint unit test', () => {
let config;
let app; let app;
let mockRegistry; let mockRegistry;
beforeAll(function(done) { beforeAll(function(done) {
const store = path.join(__dirname, '../partials/store/test-storage'); const store = path.join(__dirname, '../store/test-storage-api-spec');
const mockServerPort = 55549; const mockServerPort = 55549;
rimraf(store, async () => { rimraf(store, async () => {
const configForTest = _.clone(configDefault); const configForTest = configDefault({
configForTest.auth = { auth: {
htpasswd: { htpasswd: {
file: './test-storage/.htpasswd' file: './test-storage-api-spec/.htpasswd'
}
},
storage: store,
self_path: store,
uplinks: {
npmjs: {
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
}
} }
}; }, 'api.spec.yaml');
configForTest.uplinks = {
npmjs: { app = await endPointAPI(configForTest);
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
}
};
configForTest.self_path = store;
config = new Config(configForTest);
app = await endPointAPI(config);
mockRegistry = await mockServer(mockServerPort).init(); mockRegistry = await mockServer(mockServerPort).init();
done(); done();
}); });
@ -157,7 +158,7 @@ describe('endpoint unit test', () => {
// we need it here, because token is required // we need it here, because token is required
request(app) request(app)
.get('/vue') .get('/vue')
.set('authorization', `Bearer ${token}`) .set('authorization', buildToken(TOKEN_BEARER, token))
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
.expect(HTTP_STATUS.OK) .expect(HTTP_STATUS.OK)
.end(function(err, res) { .end(function(err, res) {
@ -171,7 +172,7 @@ describe('endpoint unit test', () => {
test('should test fails add a new user with missing name', (done) => { test('should test fails add a new user with missing name', (done) => {
const credentialsShort = _.clone(credentials); const credentialsShort = _.cloneDeep(credentials);
delete credentialsShort.name; delete credentialsShort.name;
request(app) request(app)
@ -192,7 +193,7 @@ describe('endpoint unit test', () => {
test('should test fails add a new user with missing password', (done) => { test('should test fails add a new user with missing password', (done) => {
const credentialsShort = _.clone(credentials); const credentialsShort = _.cloneDeep(credentials);
delete credentialsShort.password; delete credentialsShort.password;
request(app) request(app)
@ -213,7 +214,7 @@ describe('endpoint unit test', () => {
}); });
test('should test add a new user with login', (done) => { test('should test add a new user with login', (done) => {
const newCredentials = _.clone(credentials); const newCredentials = _.cloneDeep(credentials);
newCredentials.name = 'jotaNew'; newCredentials.name = 'jotaNew';
request(app) request(app)
@ -248,7 +249,7 @@ describe('endpoint unit test', () => {
test('should test fails add a new user with wrong password', (done) => { test('should test fails add a new user with wrong password', (done) => {
const credentialsShort = _.clone(credentials); const credentialsShort = _.cloneDeep(credentials);
credentialsShort.password = 'failPassword'; credentialsShort.password = 'failPassword';
request(app) request(app)

View file

@ -1,12 +1,10 @@
import request from 'supertest'; import request from 'supertest';
import _ from 'lodash';
import path from 'path'; import path from 'path';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import configDefault from '../partials/config/index'; import configDefault from '../partials/config/index';
import publishMetadata from '../partials/publish-api'; import publishMetadata from '../partials/publish-api';
import forbiddenPlace from '../partials/forbidden-place'; import forbiddenPlace from '../partials/forbidden-place';
import Config from '../../../src/lib/config';
import endPointAPI from '../../../src/api/index'; import endPointAPI from '../../../src/api/index';
import { HEADERS, API_ERROR, HTTP_STATUS, HEADER_TYPE, DIST_TAGS} from '../../../src/lib/constants'; import { HEADERS, API_ERROR, HTTP_STATUS, HEADER_TYPE, DIST_TAGS} from '../../../src/lib/constants';
@ -18,7 +16,6 @@ require('../../../src/lib/logger').setup([]);
const credentials = { name: 'user-web', password: 'secretPass' }; const credentials = { name: 'user-web', password: 'secretPass' };
describe('endpoint web unit test', () => { describe('endpoint web unit test', () => {
let config;
let app; let app;
let mockRegistry; let mockRegistry;
@ -26,21 +23,21 @@ describe('endpoint web unit test', () => {
const store = path.join(__dirname, '../store/test-storage-web'); const store = path.join(__dirname, '../store/test-storage-web');
const mockServerPort = 55544; const mockServerPort = 55544;
rimraf(store, async () => { rimraf(store, async () => {
const configForTest = _.clone(configDefault); const configForTest = configDefault({
configForTest.auth = { auth: {
htpasswd: { htpasswd: {
file: './test-storage-web/.htpasswd' file: './test-storage-web/.htpasswd'
} }
}; },
configForTest.storage = path.join(__dirname, '../store/test-storage-web'); storage: path.join(__dirname, '../store/test-storage-web'),
configForTest.uplinks = { uplinks: {
npmjs: { npmjs: {
url: `http://${DOMAIN_SERVERS}:${mockServerPort}` url: `http://${DOMAIN_SERVERS}:${mockServerPort}`
} }
}; },
configForTest.self_path = store; self_path: store
config = new Config(configForTest); }, 'api.web.spec.yaml');
app = await endPointAPI(config); app = await endPointAPI(configForTest);
mockRegistry = await mockServer(mockServerPort).init(); mockRegistry = await mockServer(mockServerPort).init();
done(); done();
}); });
@ -52,7 +49,7 @@ describe('endpoint web unit test', () => {
}); });
describe('Registry WebUI endpoints', () => { describe('Registry WebUI endpoints', () => {
beforeAll(async function() { beforeAll(async () => {
await request(app) await request(app)
.put('/@scope%2fpk1-test') .put('/@scope%2fpk1-test')
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)

View file

@ -22,7 +22,7 @@ import {parseConfigurationFile} from '../__helper';
import type {IAuth, } from '../../../types/index'; import type {IAuth, } from '../../../types/index';
import type {Config, Security, RemoteUser} from '@verdaccio/types'; import type {Config, Security, RemoteUser} from '@verdaccio/types';
setup(configExample.logs); setup([]);
describe('Auth utilities', () => { describe('Auth utilities', () => {
const parseConfigurationSecurityFile = (name) => { const parseConfigurationSecurityFile = (name) => {
@ -31,7 +31,7 @@ describe('Auth utilities', () => {
function getConfig(configFileName: string, secret: string) { function getConfig(configFileName: string, secret: string) {
const conf = parseConfigFile(parseConfigurationSecurityFile(configFileName)); const conf = parseConfigFile(parseConfigurationSecurityFile(configFileName));
const secConf= _.merge(configExample, conf); const secConf= _.merge(configExample(), conf);
secConf.secret = secret; secConf.secret = secret;
const config: Config = new AppConfig(secConf); const config: Config = new AppConfig(secConf);

View file

@ -1,26 +1,31 @@
import _ from 'lodash';
// @flow // @flow
import Auth from '../../../src/lib/auth'; import Auth from '../../../src/lib/auth';
// $FlowFixMe // $FlowFixMe
import configExample from '../partials/config/index'; import _configExample from '../partials/config/index';
// $FlowFixMe // $FlowFixMe
import configPlugins from '../partials/config/plugin'; import _configPlugins from '../partials/config/plugin';
import AppConfig from '../../../src/lib/config'; import AppConfig from '../../../src/lib/config';
import {setup} from '../../../src/lib/logger'; import {setup} from '../../../src/lib/logger';
import type {IAuth} from '../../../types/index'; import type {IAuth} from '../../../types/index';
import type {Config} from '@verdaccio/types'; import type {Config} from '@verdaccio/types';
const authConfig = Object.assign({}, configExample); setup([]);
// avoid noisy log output
authConfig.logs = [{type: 'stdout', format: 'pretty', level: 'error'}];
setup(configExample.logs);
describe('AuthTest', () => { describe('AuthTest', () => {
let configExample;
let configPlugins;
beforeEach(() => {
configExample = _configExample({
logs: [{type: 'stdout', format: 'pretty', level: 'error'}]
});
configPlugins = _.cloneDeep(_configPlugins);
});
test('should be defined', () => { test('should be defined', () => {
const config: Config = new AppConfig(authConfig); const config: Config = new AppConfig(configExample);
const auth: IAuth = new Auth(config); const auth: IAuth = new Auth(config);
expect(auth).toBeDefined(); expect(auth).toBeDefined();

View file

@ -18,7 +18,7 @@ describe('basic system test', () => {
beforeAll(async function(done) { beforeAll(async function(done) {
app.use(await endPointAPI(config)); app.use(await endPointAPI(config()));
server.listen(0, function() { server.listen(0, function() {
port = server.address().port; port = server.address().port;

View file

@ -27,7 +27,7 @@ describe('startServer via API', () => {
const version = '1.0.0'; const version = '1.0.0';
const port = '6000'; const port = '6000';
await startServer(_.clone(config), port, store, version, serverName, await startServer(config(), port, store, version, serverName,
(webServer, addrs, pkgName, pkgVersion) => { (webServer, addrs, pkgName, pkgVersion) => {
expect(webServer).toBeDefined(); expect(webServer).toBeDefined();
expect(addrs).toBeDefined(); expect(addrs).toBeDefined();
@ -49,7 +49,7 @@ describe('startServer via API', () => {
const address = 'https://www.domain.com:443'; const address = 'https://www.domain.com:443';
const realProcess = process; const realProcess = process;
const conf = _.clone(config); const conf = config();
conf.https = {}; conf.https = {};
// save process to catch exist // save process to catch exist
const exitMock = jest.fn(); const exitMock = jest.fn();

View file

@ -2,6 +2,7 @@
import rimRaf from 'rimraf'; import rimRaf from 'rimraf';
import path from 'path'; import path from 'path';
import LocalStorage from '../../../src/lib/local-storage'; import LocalStorage from '../../../src/lib/local-storage';
import AppConfig from '../../../src/lib/config'; import AppConfig from '../../../src/lib/config';
// $FlowFixMe // $FlowFixMe
@ -27,8 +28,10 @@ describe('LocalStorage', () => {
const tarballName2: string = `${pkgName}-add-tarball-1.0.5.tgz`; const tarballName2: string = `${pkgName}-add-tarball-1.0.5.tgz`;
const getStorage = (LocalStorageClass = LocalStorage) => { const getStorage = (LocalStorageClass = LocalStorage) => {
const config: Config = new AppConfig(configExample); const config: Config = new AppConfig(configExample({
config.self_path = path.join('../partials/store'); self_path: path.join('../partials/store')
}));
return new LocalStorageClass(config, Logger.logger); return new LocalStorageClass(config, Logger.logger);
} }
@ -262,7 +265,7 @@ describe('LocalStorage', () => {
// $FlowFixMe // $FlowFixMe
MockLocalStorage.prototype._writePackage = jest.fn(LocalStorage.prototype._writePackage) MockLocalStorage.prototype._writePackage = jest.fn(LocalStorage.prototype._writePackage)
_storage = getStorage(MockLocalStorage); _storage = getStorage(MockLocalStorage);
rimRaf(path.join(configExample.storage, pkgName), async () => { rimRaf(path.join(configExample().storage, pkgName), async () => {
await addPackageToStore(pkgName, generatePackageTemplate(pkgName)); await addPackageToStore(pkgName, generatePackageTemplate(pkgName));
await addNewVersion(pkgName, '1.0.1'); await addNewVersion(pkgName, '1.0.1');
await addNewVersion(pkgName, version); await addNewVersion(pkgName, version);

View file

@ -1,8 +1,7 @@
import Search from '../../../src/lib/search'; import Search from '../../../src/lib/search';
import Config from '../../../src/lib/config'; import Config from '../../../src/lib/config';
import Storage from '../../../src/lib/storage'; import Storage from '../../../src/lib/storage';
import buildConfig from '../partials/config/index';
let config_hash = require('../partials/config/index');
require('../../../src/lib/logger').setup([]); require('../../../src/lib/logger').setup([]);
@ -33,7 +32,7 @@ let packages = [
describe('search', () => { describe('search', () => {
beforeAll(async function() { beforeAll(async function() {
let config = new Config(config_hash); let config = new Config(buildConfig());
this.storage = new Storage(config); this.storage = new Storage(config);
await this.storage.init(config); await this.storage.init(config);
Search.configureStorage(this.storage); Search.configureStorage(this.storage);

View file

@ -1,6 +1,5 @@
// @flow // @flow
import _ from 'lodash';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
@ -16,19 +15,21 @@ import {API_ERROR, HTTP_STATUS} from '../../../src/lib/constants';
import {mockServer} from './mock'; import {mockServer} from './mock';
import {DOMAIN_SERVERS} from '../../functional/config.functional'; import {DOMAIN_SERVERS} from '../../functional/config.functional';
setup(configExample.logs); setup([]);
const storagePath = path.join(__dirname, '../partials/store/test-storage-store.spec'); const storagePath = path.join(__dirname, '../partials/store/test-storage-store.spec');
const mockServerPort: number = 55548; const mockServerPort: number = 55548;
const generateStorage = async function(port = mockServerPort, configDefault = configExample) { const generateStorage = async function(port = mockServerPort) {
const storageConfig = _.clone(configDefault); const storageConfig = configExample({
storageConfig.self_path = __dirname; self_path: __dirname,
storageConfig.storage = storagePath; storage: storagePath,
storageConfig.uplinks = { uplinks: {
npmjs: { npmjs: {
url: `http://${DOMAIN_SERVERS}:${port}` url: `http://${DOMAIN_SERVERS}:${port}`
}
} }
}; }, 'store.spec.yaml');
const config: Config = new AppConfig(storageConfig); const config: Config = new AppConfig(storageConfig);
const store: IStorageHandler = new Storage(config); const store: IStorageHandler = new Storage(config);
await store.init(config); await store.init(config);
@ -100,11 +101,14 @@ describe('StorageTest', () => {
const storage: IStorageHandler = await generateStorage(); const storage: IStorageHandler = await generateStorage();
const metadataSource = path.join(__dirname, '../partials/metadata'); const metadataSource = path.join(__dirname, '../partials/metadata');
const metadataPath = path.join(storagePath, 'npm_test/package.json'); const metadataPath = path.join(storagePath, 'npm_test/package.json');
fs.mkdirSync(path.join(storagePath, 'npm_test')); fs.mkdirSync(path.join(storagePath, 'npm_test'));
fs.writeFileSync(metadataPath, fs.readFileSync(metadataSource)); fs.writeFileSync(metadataPath, fs.readFileSync(metadataSource));
const metadata = JSON.parse(fs.readFileSync(metadataPath).toString()); const metadata = JSON.parse(fs.readFileSync(metadataPath).toString());
// $FlowFixMe // $FlowFixMe
storage.localStorage.updateVersions = jest.fn(storage.localStorage.updateVersions); storage.localStorage.updateVersions = jest.fn(storage.localStorage.updateVersions);
expect(metadata).toBeDefined();
console.log("M-->", metadata);
storage._syncUplinksMetadata('npm_test', metadata, {}, (err) => { storage._syncUplinksMetadata('npm_test', metadata, {}, (err) => {
expect(err).toBeNull(); expect(err).toBeNull();
expect(storage.localStorage.updateVersions).not.toHaveBeenCalled(); expect(storage.localStorage.updateVersions).not.toHaveBeenCalled();

View file

@ -21,7 +21,7 @@ describe('UpStorge', () => {
url: `http://0.0.0.0:${mockServerPort}` url: `http://0.0.0.0:${mockServerPort}`
}; };
const generateProxy = (config: UpLinkConf = uplinkDefault) => { const generateProxy = (config: UpLinkConf = uplinkDefault) => {
const appConfig: Config = new AppConfig(configExample); const appConfig: Config = new AppConfig(configExample());
return new ProxyStorage(config, appConfig); return new ProxyStorage(config, appConfig);
}; };

View file

@ -1,59 +1,12 @@
import _ from 'lodash';
import path from 'path'; import path from 'path';
import {parseConfigFile} from '../../../../src/lib/utils';
const config = {
storage: path.join(__dirname, '../store/test-storage'),
uplinks: {
'npmjs': {
'url': 'http://localhost:4873/'
}
},
packages: {
'@*/*': {
access: '$all',
publish: '$all',
proxy: 'npmjs'
},
'forbidden-place': { export default (options, url = 'default.yaml') => {
access: 'nobody', const locationFile = path.join(__dirname, `../config/yaml/${url}`);
publish: '$all' const config = parseConfigFile(locationFile);
},
'react': { return _.assign({}, _.cloneDeep(config), options);
access: '$all', }
publish: '$all',
proxy: 'npmjs'
},
'corrupted-package': {
access: '$all',
publish: '$all',
proxy: 'npmjs'
},
'jquery': {
access: '$all',
publish: '$all',
proxy: 'npmjs'
},
'auth-package': {
access: '$authenticated',
publish: '$authenticated'
},
'vue': {
access: '$authenticated',
publish: '$authenticated',
proxy: 'npmjs'
},
'*': {
access: '$all',
publish: '$all'
},
},
logs: [
{type: 'stdout', format: 'pretty', level: 'warn'},
],
};
module.exports = config;

View file

@ -1,8 +1,9 @@
import path from 'path'; import path from 'path';
import config from './index';
module.exports = { module.exports = {
...require('./index'), ...config(),
auth: { auth: {
[`${path.join(__dirname, '../plugin/authenticate')}`]: { } [`${path.join(__dirname, '../plugin/authenticate')}`]: { }
} }

View file

@ -0,0 +1,31 @@
storage: ./storage_default_storage
uplinks:
npmjs:
url: http://localhost:4873/
packages:
'@*/*':
access: $all
publish: $all
unpublish: $all
proxy: npmjs
'auth-package':
access: $authenticated
publish: $authenticated
'forbidden-place':
access: nobody
publish: $all
'vue':
access: $authenticated
publish: $authenticated
proxy: npmjs
'jquery':
access: $all
publish: $all
proxy: npmjs
'*':
access: $all
publish: $all
unpublish: xxx
proxy: npmjs
logs:
- { type: stdout, format: pretty, level: error }

View file

@ -0,0 +1,20 @@
storage: ./storage_default_storage
uplinks:
npmjs:
url: http://localhost:4873/
packages:
'@*/*':
access: $all
publish: $all
proxy: npmjs
unpublish: npmjs
'forbidden-place':
access: nobody
publish: $all
'*':
access: $all
publish: $all
unpublish: xxx
proxy: npmjs
logs:
- { type: stdout, format: pretty, level: warn }

View file

@ -0,0 +1,38 @@
storage: ./storage_default_storage
uplinks:
npmjs:
url: http://localhost:4873/
packages:
'@*/*':
access: $all
publish: $all
proxy: npmjs
'forbidden-place':
access: nobody
publish: $all
'react':
access: $all
publish: $all
proxy: npmjs
'corrupted-package':
access: $all
publish: $all
proxy: npmjs
'jquery':
access: $all
publish: $all
proxy: npmjs
'auth-package':
access: $authenticated
publish: $authenticated
'vue':
access: $authenticated
publish: $authenticated
proxy: npmjs
'*':
access: $all
publish: $all
proxy: npmjs
logs:
- { type: stdout, format: pretty, level: warn }

View file

@ -0,0 +1,22 @@
uplinks:
npmjs:
url: http://localhost:4873/
packages:
'@*/*':
access: $all
publish: $all
proxy: npmjs
'corrupted-package':
access: $all
publish: $all
proxy: npmjs
'jquery':
access: $all
publish: $all
proxy: npmjs
'*':
access: $all
publish: $all
proxy: npmjs
logs:
- { type: stdout, format: pretty, level: warn }

View file

@ -1,163 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<NotFound /> component should load the component in default state 1`] = ` exports[`<NotFound /> component should load the component in default state 1`] = `ShallowWrapper {}`;
ShallowWrapper {
Symbol(enzyme.__root__): ShallowWrapper {
Symbol(enzyme.__root__): [Circular],
Symbol(enzyme.__unrendered__): <BrowserRouter>
<withRouter(WithTheme(WithWidth(NotFound))) />
</BrowserRouter>,
Symbol(enzyme.__renderer__): Object {
"batchedUpdates": [Function],
"getNode": [Function],
"render": [Function],
"simulateError": [Function],
"simulateEvent": [Function],
"unmount": [Function],
},
Symbol(enzyme.__node__): Object {
"instance": null,
"key": undefined,
"nodeType": "class",
"props": Object {
"children": <withRouter(WithTheme(WithWidth(NotFound))) />,
"history": Object {
"action": "POP",
"block": [Function],
"createHref": [Function],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
},
},
"ref": null,
"rendered": Object {
"instance": null,
"key": undefined,
"nodeType": "function",
"props": Object {},
"ref": null,
"rendered": null,
"type": [Function],
},
"type": [Function],
},
Symbol(enzyme.__nodes__): Array [
Object {
"instance": null,
"key": undefined,
"nodeType": "class",
"props": Object {
"children": <withRouter(WithTheme(WithWidth(NotFound))) />,
"history": Object {
"action": "POP",
"block": [Function],
"createHref": [Function],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
},
},
"ref": null,
"rendered": Object {
"instance": null,
"key": undefined,
"nodeType": "function",
"props": Object {},
"ref": null,
"rendered": null,
"type": [Function],
},
"type": [Function],
},
],
Symbol(enzyme.__options__): Object {
"adapter": ReactSixteenAdapter {
"options": Object {
"enableComponentDidUpdateOnSetState": true,
"lifecycles": Object {
"componentDidUpdate": Object {
"onSetState": true,
},
"getDerivedStateFromProps": true,
"getSnapshotBeforeUpdate": true,
"setState": Object {
"skipsComponentDidUpdateOnNullish": true,
},
},
},
},
"attachTo": undefined,
"hydrateIn": undefined,
},
},
Symbol(enzyme.__unrendered__): null,
Symbol(enzyme.__renderer__): Object {
"batchedUpdates": [Function],
"getNode": [Function],
"render": [Function],
"simulateError": [Function],
"simulateEvent": [Function],
"unmount": [Function],
},
Symbol(enzyme.__node__): Object {
"instance": null,
"key": undefined,
"nodeType": "function",
"props": Object {},
"ref": null,
"rendered": null,
"type": [Function],
},
Symbol(enzyme.__nodes__): Array [
Object {
"instance": null,
"key": undefined,
"nodeType": "function",
"props": Object {},
"ref": null,
"rendered": null,
"type": [Function],
},
],
Symbol(enzyme.__options__): Object {
"adapter": ReactSixteenAdapter {
"options": Object {
"enableComponentDidUpdateOnSetState": true,
"lifecycles": Object {
"componentDidUpdate": Object {
"onSetState": true,
},
"getDerivedStateFromProps": true,
"getSnapshotBeforeUpdate": true,
"setState": Object {
"skipsComponentDidUpdateOnNullish": true,
},
},
},
},
"attachTo": undefined,
"hydrateIn": undefined,
},
}
`;

898
yarn.lock

File diff suppressed because it is too large Load diff