diff --git a/package.json b/package.json index 78ddc0c87..2ac586b36 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "devDependencies": { "@commitlint/cli": "6.1.3", "@commitlint/config-conventional": "6.1.3", - "@verdaccio/types": "3.0.0", + "@verdaccio/types": "3.0.1", "babel-cli": "6.26.0", "babel-core": "6.26.0", "babel-eslint": "8.2.2", diff --git a/src/api/index.js b/src/api/index.js index 5b384a0b5..d69802a2f 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -15,13 +15,13 @@ import type {$ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler, import type {Config as IConfig} from '@verdaccio/types'; import {ErrorCode} from '../lib/utils'; import {API_ERROR, HTTP_STATUS} from '../lib/constants'; +import AppConfig from '../lib/config'; const LoggerApp = require('../lib/logger'); -const Config = require('../lib/config'); const Middleware = require('./middleware'); const Cats = require('../lib/status-cats'); -const defineAPI = function(config: Config, storage: IStorageHandler) { +const defineAPI = function(config: IConfig, storage: IStorageHandler) { const auth: IAuth = new Auth(config); const app: $Application = express(); // run in production mode by default, just in case @@ -103,7 +103,7 @@ const defineAPI = function(config: Config, storage: IStorageHandler) { export default async function(configHash: any) { LoggerApp.setup(configHash.logs); - const config: IConfig = new Config(configHash); + const config: IConfig = new AppConfig(configHash); const storage: IStorageHandler = new Storage(config); // waits until init calls have been intialized await storage.init(config); diff --git a/src/lib/auth.js b/src/lib/auth.js index 1898e6804..ee4b80a8e 100644 --- a/src/lib/auth.js +++ b/src/lib/auth.js @@ -9,6 +9,7 @@ import type {Config, Logger, Callback} from '@verdaccio/types'; import type {$Response, NextFunction} from 'express'; import type {$RequestExtend, JWTPayload} from '../../types'; import {API_ERROR, ROLES} from './constants'; +import {getMatchedPackagesSpec} from './config-utils'; const LoggerApi = require('./logger'); @@ -146,7 +147,7 @@ class Auth { allow_access(packageName: string, user: string, callback: Callback) { let plugins = this.plugins.slice(0); // $FlowFixMe - let pkg = Object.assign({name: packageName}, this.config.getMatchedPackagesSpec(packageName)); + let pkg = Object.assign({name: packageName}, getMatchedPackagesSpec(packageName, this.config.packages)); (function next() { const plugin = plugins.shift(); @@ -175,7 +176,7 @@ class Auth { allow_publish(packageName: string, user: string, callback: Callback) { let plugins = this.plugins.slice(0); // $FlowFixMe - let pkg = Object.assign({name: packageName}, this.config.getMatchedPackagesSpec(packageName)); + let pkg = Object.assign({name: packageName}, getMatchedPackagesSpec(packageName, this.config.packages)); (function next() { const plugin = plugins.shift(); diff --git a/src/lib/bootstrap.js b/src/lib/bootstrap.js index 358177a19..76784e803 100644 --- a/src/lib/bootstrap.js +++ b/src/lib/bootstrap.js @@ -64,9 +64,12 @@ export function getListListenAddresses(argListen: string, configListen: mixed) { * @param {String} pkgVersion * @param {String} pkgName */ -function startVerdaccio(config: any, cliListen: string, - configPath: string, pkgVersion: string, - pkgName: string, callback: Callback) { +function startVerdaccio(config: any, + cliListen: string, + configPath: string, + pkgVersion: string, + pkgName: string, + callback: Callback) { if (isObject(config) === false) { throw new Error('config file must be an object'); } diff --git a/src/lib/config-utils.js b/src/lib/config-utils.js index 0a9c38a22..e560552e2 100644 --- a/src/lib/config-utils.js +++ b/src/lib/config-utils.js @@ -1,10 +1,12 @@ // @flow - import _ from 'lodash'; -import minimatch from 'minimatch'; import assert from 'assert'; +import minimatch from 'minimatch'; + import {ErrorCode} from './utils'; +import type {PackageList} from '@verdaccio/types'; +import type {MatchedPackage} from '../../types'; const BLACKLIST = { all: true, anonymous: true, @@ -38,17 +40,6 @@ export function normalizeUserlist(oldFormat: any, newFormat: any) { return _.flatten(result); } -export function getMatchedPackagesSpec(packages: any, pkg: any) { - for (let i in packages) { - // $FlowFixMe - if (minimatch.makeRe(i).exec(pkg)) { - return packages[i]; - } - } - - return {}; -} - export function uplinkSanityCheck(uplinks: any, users: any = BLACKLIST) { const newUplinks = _.clone(uplinks); let newUsers = _.clone(users); @@ -88,8 +79,36 @@ export function sanityCheckUplinksProps(configUpLinks: any) { return uplinks; } -export function normalisePackageAccess(packages: any): any { - const normalizedPkgs: any = {...packages}; +/** + * Check whether an uplink can proxy + */ +export function hasProxyTo(pkg: string, upLink: string, packages: PackageList): boolean { + const matchedPkg: MatchedPackage = (getMatchedPackagesSpec(pkg, packages): MatchedPackage); + const proxyList = typeof matchedPkg !== 'undefined' ? matchedPkg.proxy : []; + if (proxyList) { + return proxyList.reduce((prev, curr) => { + if (upLink === curr) { + return true; + } + return prev; + }, false); + } + + return false; +} + +export function getMatchedPackagesSpec(pkg: string, packages: PackageList): MatchedPackage { + for (let i in packages) { + // $FlowFixMe + if (minimatch.makeRe(i).exec(pkg)) { + return packages[i]; + } + } + return; +} + +export function normalisePackageAccess(packages: PackageList): PackageList { + const normalizedPkgs: PackageList = {...packages}; // add a default rule for all packages to make writing plugins easier if (_.isNil(normalizedPkgs['**'])) { normalizedPkgs['**'] = {}; diff --git a/src/lib/config.js b/src/lib/config.js index 0501a61cc..823b57be4 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -1,12 +1,25 @@ +// @flow + import _ from 'lodash'; import assert from 'assert'; -import minimatch from 'minimatch'; import {generateRandomHexString} from './crypto-utils'; -import {normalisePackageAccess, sanityCheckUplinksProps, uplinkSanityCheck} from './config-utils'; +import { + getMatchedPackagesSpec, + normalisePackageAccess, + sanityCheckUplinksProps, + uplinkSanityCheck} from './config-utils'; import {getUserAgent, isObject} from './utils'; import {APP_ERROR} from './constants'; +import type { + PackageList, + Config as AppConfig, + Logger, + } from '@verdaccio/types'; + +import type {MatchedPackage, StartUpConfig} from '../../types'; + const LoggerApi = require('./logger'); const strategicConfigProps = ['uplinks', 'packages']; const allowedEnvConfig = ['http_proxy', 'https_proxy', 'no_proxy']; @@ -14,10 +27,24 @@ const allowedEnvConfig = ['http_proxy', 'https_proxy', 'no_proxy']; /** * Coordinates the application configuration */ -class Config { - constructor(config) { +class Config implements AppConfig { + logger: Logger; + user_agent: string; + secret: string; + uplinks: any; + packages: PackageList; + users: any; + server_id: string; + self_path: string; + storage: string | void; + $key: any; + $value: any; + + constructor(config: StartUpConfig) { const self = this; this.logger = LoggerApi.logger; + this.self_path = config.self_path; + this.storage = config.storage; for (let configProp in config) { if (self[configProp] == null) { @@ -44,7 +71,7 @@ class Config { this.uplinks = sanityCheckUplinksProps(uplinkSanityCheck(this.uplinks)); if (_.isNil(this.users) === false) { - this.logger.warn(`[users]: property on configuration file + this.logger.warn(`[users]: property on configuration file is not longer supported, property being ignored`); } @@ -63,42 +90,18 @@ class Config { } } - /** - * Check whether an uplink can proxy - * @param {String} pkg package anem - * @param {*} upLink - * @return {Boolean} - */ - hasProxyTo(pkg, upLink) { - return (this.getMatchedPackagesSpec(pkg).proxy || []).reduce(function(prev, curr) { - if (upLink === curr) { - return true; - } - return prev; - }, false); - } - /** * Check for package spec - * @param {String} pkg package name - * @return {Object} */ - getMatchedPackagesSpec(pkg) { - for (let i in this.packages) { - if (minimatch.makeRe(i).exec(pkg)) { - return this.packages[i]; - } - } - return {}; + getMatchedPackagesSpec(pkg: string): MatchedPackage { + return getMatchedPackagesSpec(pkg, this.packages); } /** * Store or create whether recieve a secret key - * @param {String} secret - * @return {String} */ - checkSecretKey(secret) { - if (_.isString(secret) && secret !== '') { + checkSecretKey(secret: string): string { + if (_.isString(secret) && _.isEmpty(secret) === false) { this.secret = secret; return secret; } @@ -109,4 +112,4 @@ class Config { } } -module.exports = Config; +export default Config; diff --git a/src/lib/storage.js b/src/lib/storage.js index e0745aad7..e66173941 100644 --- a/src/lib/storage.js +++ b/src/lib/storage.js @@ -26,6 +26,7 @@ Callback, Logger, } from '@verdaccio/types'; import type {IReadTarball, IUploadTarball} from '@verdaccio/streams'; +import {hasProxyTo} from './config-utils'; const LoggerApi = require('../lib/logger'); @@ -412,9 +413,9 @@ class Storage implements IStorageHandler { packageInfo = generatePackageTemplate(name); } - for (let up in this.uplinks) { - if (this.config.hasProxyTo(name, up)) { - upLinks.push(this.uplinks[up]); + for (let uplink in this.uplinks) { + if (hasProxyTo(name, uplink, this.config.packages)) { + upLinks.push(this.uplinks[uplink]); } } diff --git a/test/unit/api/config-utils.spec.js b/test/unit/api/config-utils.spec.js index ab2972f8c..6382d8483 100644 --- a/test/unit/api/config-utils.spec.js +++ b/test/unit/api/config-utils.spec.js @@ -11,7 +11,7 @@ describe('Config Utilities', () => { return path.join(__dirname, `../partials/config/yaml/${name}.yaml`); }; - describe('getMatchedPackagesSpec', () => { + describe('normalisePackageAccess', () => { test('should test basic conversion', ()=> { const {packages} = parseConfigFile(parsePartial('pkgs-basic')); const access = normalisePackageAccess(packages); @@ -58,8 +58,14 @@ describe('Config Utilities', () => { const react = access['react-*']; expect(react).toBeDefined(); + expect(react.access).toBeDefined(); + // $FlowFixMe expect(react.access[0]).toBe(ROLES.$ALL); + expect(react.publish).toBeDefined(); + // $FlowFixMe); expect(react.publish[0]).toBe('admin'); + expect(react.proxy).toBeDefined(); + // $FlowFixMe expect(react.proxy[0]).toBe('uplink2'); expect(react.storage).toBeDefined(); diff --git a/test/unit/api/search.spec.js b/test/unit/api/search.spec.js index 34e66a199..43cc61cb9 100644 --- a/test/unit/api/search.spec.js +++ b/test/unit/api/search.spec.js @@ -1,10 +1,10 @@ - - import assert from 'assert'; import Search from '../../../src/lib/search'; +import Config from '../../../src/lib/config'; import Storage from '../../../src/lib/storage'; + let config_hash = require('../partials/config/index'); -let Config = require('../../../src/lib/config'); + require('../../../src/lib/logger').setup([]); diff --git a/types/index.js b/types/index.js index 091088430..a4698005b 100644 --- a/types/index.js +++ b/types/index.js @@ -8,6 +8,7 @@ import type { MergeTags, Config, Logger, + PackageAccess, Package} from '@verdaccio/types'; import type { IUploadTarball, @@ -95,6 +96,20 @@ export interface IStorageHandler { _updateVersionsHiddenUpLink(versions: Versions, upLink: IProxy): void; } +// export interface ConfigHandler { +// checkSecretKey(token: string): string; +// hasProxyTo(pkg: string, upLink: string): boolean; +// getMatchedPackagesSpec(storage: string): verdaccio$PackageAccess | void; +// [key: string]: number; +// } + +export type StartUpConfig = { + storage: string; + self_path: string; +} + +export type MatchedPackage = PackageAccess | void; + export interface IStorage { config: Config; localData: ILocalData; diff --git a/yarn.lock b/yarn.lock index 49bc26051..adfe7ae1b 100644 Binary files a/yarn.lock and b/yarn.lock differ