diff --git a/.eslintrc b/.eslintrc index b4895bfdc..8c1a16585 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,18 +1,102 @@ { "extends": [ - "@verdaccio" + "eslint:recommended", + "google", + "plugin:react/recommended", + "plugin:jest/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:import/typescript", + "plugin:jsx-a11y/recommended", + "prettier" ], + "plugins": ["import", "jest", "jsx-a11y", "react-hooks"], + "env": { + "es6": true, + "node": true, + "jest": true + }, + "globals": { + "__APP_VERSION__": true + }, + "parserOptions": { + "allowImportExportEverywhere": true, + "sourceType": "module", + "ecmaVersion": 11, + "ecmaFeatures": { + "impliedStrict": true, + "jsx": true + } + }, + "settings": { + "import/resolver": { + "node": { + "extensions": [".js", ".jsx", ".ts", ".tsx"] + } + } + }, + "parser": "@typescript-eslint/parser", "rules": { - "@typescript-eslint/no-var-requires": 0, + "curly": ["error", "all"], + "react/prop-types": 0, + "jest/no-export": 0, + "jest/no-test-callback": 0, + "jest/expect-expect": 0, + "jest/no-try-expect": 0, + "jest/no-done-callback": "off", + "jest/no-conditional-expect": "off", + "keyword-spacing": "off", + "no-tabs": "off", + "no-useless-escape": "off", + "padded-blocks": "off", + "require-jsdoc": "off", + "valid-jsdoc": "off", + "import/order": ["error"], + "eol-last": "error", + "no-irregular-whitespace": "error", + "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], + "no-trailing-spaces": "error", + "camelcase": "off", + "guard-for-in": "error", + "new-cap": "error", + "max-len": ["error", 160], + "no-console": ["error", { "allow": ["warn"] }], + "no-constant-condition": "error", + "no-debugger": "error", + "no-empty": "error", + "no-fallthrough": "error", + "no-invalid-this": "error", + "no-new-require": "error", + "no-undef": "error", + "no-unreachable": "error", + "no-var": "error", + "one-var": "error", + "prefer-rest-params": "error", + "prefer-spread": "error", + "handle-callback-err": 0, + "prefer-const": 0, + "@typescript-eslint/camelcase": 0, "@typescript-eslint/ban-ts-ignore": 0, + "@typescript-eslint/no-var-requires": 0, "@typescript-eslint/no-inferrable-types": 0, "@typescript-eslint/no-empty-function": 0, - "@typescript-eslint/no-this-alias": ["warn"], + "@typescript-eslint/no-this-alias": 0, "@typescript-eslint/no-use-before-define": 0, - "@typescript-eslint/array-type": ["warn"], + "@typescript-eslint/array-type": ["error"], "@typescript-eslint/no-explicit-any": 0, "@typescript-eslint/indent": 0, - "@typescript-eslint/interface-name-prefix": 0, - "import/order": 0 + "@typescript-eslint/ban-ts-comment": 0, + "@typescript-eslint/ban-types": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + + // rules to fix + "no-unused-vars": ["warn", { "vars": "all", "args": "none" }], + "jest/no-identical-title": ["warn"], + "prefer-promise-reject-errors": ["warn"], + "jest/no-disabled-tests": ["warn"], + "jest/no-commented-out-tests": ["warn"], + "@typescript-eslint/prefer-optional-chain": ["warn"], + "@typescript-eslint/explicit-member-accessibility": ["warn"], + "@typescript-eslint/no-unused-vars": ["warn"] } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0a2c44e0..c95dd4780 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - node_version: [10, 12, 13, 14, 15] + node_version: [10, 12, 14, 15] runs-on: ubuntu-latest diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..19170b55c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,29 @@ +.cache/ +**/corrupted-package/package.json +**/corrupted.json +**/invalid.js +**/invalid.json +**/pnpm-lock.yaml +**/verdaccio-corrupted.db.json +**/wrong.package.json +/website/.cache/ +/website/crowdin/ +/website/public/ +/website/src/dictionaries/ +CHANGELOG.md +CONTRIBUTORS.md +node_modules/ +**/coverage/** +**/build/*.js +test/unit/partials/* +build/* +.github/ +.vscode/ +wiki/ +.yarnrc.yml +yarn-error.log +.yarn/ +test/functional/store/* +storage_default_storage/* +docker-examples/ +.prettierignore diff --git a/.prettierrc b/.prettierrc.json similarity index 62% rename from .prettierrc rename to .prettierrc.json index 2d0bc4dd8..96e3b8fbd 100644 --- a/.prettierrc +++ b/.prettierrc.json @@ -1,12 +1,11 @@ { + "endOfLine": "lf", "useTabs": false, - "printWidth": 160, + "printWidth": 180, "tabWidth": 2, "singleQuote": true, - "requirePragma": true, "bracketSpacing": true, "jsxBracketSameLine": true, "trailingComma": "es5", - "semi": true, - "parser": "typescript" + "semi": true } diff --git a/jestEnvironment.js b/jestEnvironment.js index d293d5d71..aeb87e8f6 100644 --- a/jestEnvironment.js +++ b/jestEnvironment.js @@ -1 +1 @@ -require.requireActual('babel/polyfill'); +jest.requireActual('babel/polyfill'); diff --git a/package.json b/package.json index acb339280..45493abb2 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,8 @@ "@types/node": "12.12.21", "@types/request": "2.48.3", "@types/semver": "6.2.0", - "@typescript-eslint/eslint-plugin": "2.12.0", + "@typescript-eslint/eslint-plugin": "4.13.0", + "@typescript-eslint/parser": "4.13.0", "@verdaccio/eslint-config": "^8.5.0", "@verdaccio/types": "^9.7.2", "all-contributors-cli": "6.20.0", @@ -100,7 +101,17 @@ "codecov": "3.8.1", "cross-env": "7.0.3", "detect-secrets": "1.0.6", - "eslint": "6.8.0", + "eslint": "7.19.0", + "eslint-config-google": "0.14.0", + "eslint-config-prettier": "7.2.0", + "eslint-plugin-babel": "5.3.1", + "eslint-plugin-import": "2.22.1", + "eslint-plugin-jest": "24.1.3", + "eslint-plugin-jsx-a11y": "6.4.1", + "eslint-plugin-react": "7.22.0", + "eslint-plugin-react-hooks": "4.2.0", + "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-verdaccio": "9.6.1", "fs-extra": "9.1.0", "get-stdin": "7.0.0", "husky": "2.7.0", @@ -111,7 +122,7 @@ "lint-staged": "8.2.1", "lockfile-lint": "4.3.7", "nock": "12.0.3", - "prettier": "1.19.1", + "prettier": "2.2.1", "puppeteer": "5.5.0", "rimraf": "3.0.2", "selfsigned": "1.10.8", @@ -139,6 +150,8 @@ "type-check": "tsc --noEmit", "type-check:watch": "yarn run type-check -- --watch", "pretest": "yarn run code:build", + "format": "prettier --single-quote --trailing-comma none --write \"{src,test}/**/*.ts\"", + "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,yml,yaml,md}\" --debug-check", "test": "yarn run test:unit", "test:clean": "npx jest --clearCache", "test:unit": "cross-env NODE_ENV=test TZ=UTC FORCE_COLOR=1 jest --config ./jest.config.js --maxWorkers 2 --passWithNoTests", @@ -149,9 +162,8 @@ "pre:ci": "yarn run lint", "coverage:publish": "codecov", "lint": "yarn run type-check && yarn run lint:ts", - "lint:ts": "eslint . --ext .js,.ts", + "lint:ts": "eslint \"**/*.{js,jsx,ts,tsx}\"", "lint:lockfile": "lockfile-lint --path yarn.lock --type yarn --validate-https --allowed-hosts verdaccio npm yarn", - "format": "prettier --single-quote --trailing-comma none --write \"{src,test}/**/*.ts\"", "dev:start": "yarn babel-node --extensions \".ts,.tsx\" src/lib/cli", "code:build": "yarn babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps inline", "code:docker-build": "yarn babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\"", @@ -172,11 +184,6 @@ "lint-staged": { "relative": true, "linters": { - "*.yaml": [ - "prettier --parser yaml --no-config --single-quote --write", - "detect-secrets-launcher --baseline .secrets-baseline", - "git add" - ], "*": [ "eslint .", "prettier --write", diff --git a/src/api/debug/index.ts b/src/api/debug/index.ts index 582b6985c..2627ea2fd 100644 --- a/src/api/debug/index.ts +++ b/src/api/debug/index.ts @@ -4,20 +4,23 @@ import { $ResponseExtend, $RequestExtend, $NextFunctionVer } from '../../../type export default (app: Application, selfPath: string): void => { // Hook for tests only - app.get('/-/_debug', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - const doGarbabeCollector = _.isNil(global.gc) === false; + app.get( + '/-/_debug', + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + const doGarbabeCollector = _.isNil(global.gc) === false; - if (doGarbabeCollector) { - global.gc(); + if (doGarbabeCollector) { + global.gc(); + } + + next({ + pid: process.pid, + // @ts-ignore + main: process.mainModule.filename, + conf: selfPath, + mem: process.memoryUsage(), + gc: doGarbabeCollector + }); } - - next({ - pid: process.pid, - // @ts-ignore - main: process.mainModule.filename, - conf: selfPath, - mem: process.memoryUsage(), - gc: doGarbabeCollector, - }); - }); + ); }; diff --git a/src/api/endpoint/api/dist-tags.ts b/src/api/endpoint/api/dist-tags.ts index 01b8b8448..12508160c 100644 --- a/src/api/endpoint/api/dist-tags.ts +++ b/src/api/endpoint/api/dist-tags.ts @@ -1,22 +1,32 @@ import mime from 'mime'; import _ from 'lodash'; -import { media, allow } from '../../middleware'; -import{ Router } from 'express'; -import{ IAuth, $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types'; -import { API_MESSAGE, HTTP_STATUS, DIST_TAGS } from '../../../lib/constants'; +import { Router } from 'express'; import { VerdaccioError } from '@verdaccio/commons-api'; import { Package } from '@verdaccio/types'; +import { media, allow } from '../../middleware'; +import { + IAuth, + $ResponseExtend, + $RequestExtend, + $NextFunctionVer, + IStorageHandler +} from '../../../../types'; +import { API_MESSAGE, HTTP_STATUS, DIST_TAGS } from '../../../lib/constants'; -export default function(route: Router, auth: IAuth, storage: IStorageHandler): void { +export default function (route: Router, auth: IAuth, storage: IStorageHandler): void { const can = allow(auth); - const tag_package_version = function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): $NextFunctionVer { + const tag_package_version = function ( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer + ): $NextFunctionVer { if (_.isString(req.body) === false) { return next('route'); } const tags = {}; tags[req.params.tag] = req.body; - storage.mergeTags(req.params.package, tags, function(err: Error): $NextFunctionVer { + storage.mergeTags(req.params.package, tags, function (err: Error): $NextFunctionVer { if (err) { return next(err); } @@ -28,48 +38,74 @@ export default function(route: Router, auth: IAuth, storage: IStorageHandler): v // tagging a package route.put('/:package/:tag', can('publish'), media(mime.getType('json')), tag_package_version); - route.post('/-/package/:package/dist-tags/:tag', can('publish'), media(mime.getType('json')), tag_package_version); + route.post( + '/-/package/:package/dist-tags/:tag', + can('publish'), + media(mime.getType('json')), + tag_package_version + ); - route.put('/-/package/:package/dist-tags/:tag', can('publish'), media(mime.getType('json')), tag_package_version); + route.put( + '/-/package/:package/dist-tags/:tag', + can('publish'), + media(mime.getType('json')), + tag_package_version + ); - route.delete('/-/package/:package/dist-tags/:tag', can('publish'), function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - const tags = {}; - tags[req.params.tag] = null; - storage.mergeTags(req.params.package, tags, function(err: VerdaccioError): $NextFunctionVer { - if (err) { - return next(err); - } - res.status(HTTP_STATUS.CREATED); - return next({ - ok: API_MESSAGE.TAG_REMOVED, - }); - }); - }); - - route.get('/-/package/:package/dist-tags', can('access'), function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - storage.getPackage({ - name: req.params.package, - uplinksLook: true, - req, - callback: function(err: VerdaccioError, info: Package): $NextFunctionVer { + route.delete( + '/-/package/:package/dist-tags/:tag', + can('publish'), + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + const tags = {}; + tags[req.params.tag] = null; + storage.mergeTags(req.params.package, tags, function (err: VerdaccioError): $NextFunctionVer { if (err) { return next(err); } - - next(info[DIST_TAGS]); - }, - }); - }); - - route.post('/-/package/:package/dist-tags', can('publish'), function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - storage.mergeTags(req.params.package, req.body, function(err: VerdaccioError): $NextFunctionVer { - if (err) { - return next(err); - } - res.status(HTTP_STATUS.CREATED); - return next({ - ok: API_MESSAGE.TAG_UPDATED, + res.status(HTTP_STATUS.CREATED); + return next({ + ok: API_MESSAGE.TAG_REMOVED + }); }); - }); - }); + } + ); + + route.get( + '/-/package/:package/dist-tags', + can('access'), + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + storage.getPackage({ + name: req.params.package, + uplinksLook: true, + req, + callback: function (err: VerdaccioError, info: Package): $NextFunctionVer { + if (err) { + return next(err); + } + + next(info[DIST_TAGS]); + } + }); + } + ); + + route.post( + '/-/package/:package/dist-tags', + can('publish'), + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + storage.mergeTags( + req.params.package, + req.body, + function (err: VerdaccioError): $NextFunctionVer { + if (err) { + return next(err); + } + res.status(HTTP_STATUS.CREATED); + return next({ + ok: API_MESSAGE.TAG_UPDATED + }); + } + ); + } + ); } diff --git a/src/api/endpoint/api/package.ts b/src/api/endpoint/api/package.ts index c7465b9e1..1a23418dc 100644 --- a/src/api/endpoint/api/package.ts +++ b/src/api/endpoint/api/package.ts @@ -1,19 +1,31 @@ import _ from 'lodash'; +import { Router } from 'express'; +import { Config, Package } from '@verdaccio/types'; import { allow } from '../../middleware'; import { convertDistRemoteToLocalTarballUrls, getVersion, ErrorCode } from '../../../lib/utils'; import { HEADERS, DIST_TAGS, API_ERROR } from '../../../lib/constants'; -import { Router } from 'express'; -import { Config, Package } from '@verdaccio/types'; -import { IAuth, $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types'; +import { + IAuth, + $ResponseExtend, + $RequestExtend, + $NextFunctionVer, + IStorageHandler +} from '../../../../types'; -const downloadStream = (packageName: string, filename: string, storage: any, req: $RequestExtend, res: $ResponseExtend): void => { +const downloadStream = ( + packageName: string, + filename: string, + storage: any, + req: $RequestExtend, + res: $ResponseExtend +): void => { const stream = storage.getTarball(packageName, filename); - stream.on('content-length', function(content): void { + stream.on('content-length', function (content): void { res.header('Content-Length', content); }); - stream.on('error', function(err): void { + stream.on('error', function (err): void { return res.report_error(err); }); @@ -21,53 +33,70 @@ const downloadStream = (packageName: string, filename: string, storage: any, req stream.pipe(res); }; -export default function(route: Router, auth: IAuth, storage: IStorageHandler, config: Config): void { +export default function ( + route: Router, + auth: IAuth, + storage: IStorageHandler, + config: Config +): void { const can = allow(auth); // TODO: anonymous user? - route.get('/:package/:version?', can('access'), function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - const getPackageMetaCallback = function(err, metadata: Package): void { - if (err) { - return next(err); - } - metadata = convertDistRemoteToLocalTarballUrls(metadata, req, config.url_prefix); + route.get( + '/:package/:version?', + can('access'), + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + const getPackageMetaCallback = function (err, metadata: Package): void { + if (err) { + return next(err); + } + metadata = convertDistRemoteToLocalTarballUrls(metadata, req, config.url_prefix); - let queryVersion = req.params.version; - if (_.isNil(queryVersion)) { - return next(metadata); - } + let queryVersion = req.params.version; + if (_.isNil(queryVersion)) { + return next(metadata); + } - let version = getVersion(metadata, queryVersion); - if (_.isNil(version) === false) { - return next(version); - } + let version = getVersion(metadata, queryVersion); + if (_.isNil(version) === false) { + return next(version); + } - if (_.isNil(metadata[DIST_TAGS]) === false) { - if (_.isNil(metadata[DIST_TAGS][queryVersion]) === false) { - queryVersion = metadata[DIST_TAGS][queryVersion]; - version = getVersion(metadata, queryVersion); - if (_.isNil(version) === false) { - return next(version); + if (_.isNil(metadata[DIST_TAGS]) === false) { + if (_.isNil(metadata[DIST_TAGS][queryVersion]) === false) { + queryVersion = metadata[DIST_TAGS][queryVersion]; + version = getVersion(metadata, queryVersion); + if (_.isNil(version) === false) { + return next(version); + } } } - } - return next(ErrorCode.getNotFound(`${API_ERROR.VERSION_NOT_EXIST}: ${req.params.version}`)); - }; + return next(ErrorCode.getNotFound(`${API_ERROR.VERSION_NOT_EXIST}: ${req.params.version}`)); + }; - storage.getPackage({ - name: req.params.package, - uplinksLook: true, - req, - callback: getPackageMetaCallback, - }); - }); + storage.getPackage({ + name: req.params.package, + uplinksLook: true, + req, + callback: getPackageMetaCallback + }); + } + ); - route.get('/:scopedPackage/-/:scope/:filename', can('access'), function(req: $RequestExtend, res: $ResponseExtend): void { - const { scopedPackage, filename } = req.params; + route.get( + '/:scopedPackage/-/:scope/:filename', + can('access'), + function (req: $RequestExtend, res: $ResponseExtend): void { + const { scopedPackage, filename } = req.params; - downloadStream(scopedPackage, filename, storage, req, res); - }); + downloadStream(scopedPackage, filename, storage, req, res); + } + ); - route.get('/:package/-/:filename', can('access'), function(req: $RequestExtend, res: $ResponseExtend): void { - downloadStream(req.params.package, req.params.filename, storage, req, res); - }); + route.get( + '/:package/-/:filename', + can('access'), + function (req: $RequestExtend, res: $ResponseExtend): void { + downloadStream(req.params.package, req.params.filename, storage, req, res); + } + ); } diff --git a/src/api/endpoint/api/ping.ts b/src/api/endpoint/api/ping.ts index c9ab109df..0633c2e8a 100644 --- a/src/api/endpoint/api/ping.ts +++ b/src/api/endpoint/api/ping.ts @@ -6,8 +6,11 @@ import { Router } from 'express'; import { $RequestExtend, $ResponseExtend, $NextFunctionVer } from '../../../../types'; -export default function(route: Router): void { - route.get('/-/ping', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) { - next({}); - }); +export default function (route: Router): void { + route.get( + '/-/ping', + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) { + next({}); + } + ); } diff --git a/src/api/endpoint/api/publish.ts b/src/api/endpoint/api/publish.ts index b5d2a985c..d2a645d8c 100644 --- a/src/api/endpoint/api/publish.ts +++ b/src/api/endpoint/api/publish.ts @@ -1,20 +1,37 @@ -import _ from 'lodash'; import Path from 'path'; +import _ from 'lodash'; import mime from 'mime'; -import { API_MESSAGE, HEADERS, DIST_TAGS, API_ERROR, HTTP_STATUS } from '../../../lib/constants'; -import {validateMetadata, isObject, ErrorCode, hasDiffOneKey, isRelatedToDeprecation} from '../../../lib/utils'; -import { media, expectJson, allow } from '../../middleware'; -import { notify } from '../../../lib/notify'; -import star from './star'; - import { Router } from 'express'; import { Config, Callback, MergeTags, Version, Package } from '@verdaccio/types'; -import { IAuth, $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types'; -import { logger } from '../../../lib/logger'; -import {isPublishablePackage} from "../../../lib/storage-utils"; +import { API_MESSAGE, HEADERS, DIST_TAGS, API_ERROR, HTTP_STATUS } from '../../../lib/constants'; +import { + validateMetadata, + isObject, + ErrorCode, + hasDiffOneKey, + isRelatedToDeprecation +} from '../../../lib/utils'; +import { media, expectJson, allow } from '../../middleware'; +import { notify } from '../../../lib/notify'; -export default function publish(router: Router, auth: IAuth, storage: IStorageHandler, config: Config): void { +import { + IAuth, + $ResponseExtend, + $RequestExtend, + $NextFunctionVer, + IStorageHandler +} from '../../../../types'; +import { logger } from '../../../lib/logger'; +import { isPublishablePackage } from '../../../lib/storage-utils'; +import star from './star'; + +export default function publish( + router: Router, + auth: IAuth, + storage: IStorageHandler, + config: Config +): void { const can = allow(auth); /** @@ -76,7 +93,13 @@ 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, auth)); + router.put( + '/:package/:_rev?/:revision?', + can('publish'), + media(mime.getType('json')), + expectJson, + publishPackage(storage, config, auth) + ); /** * Un-publishing an entire package. @@ -89,13 +112,29 @@ export default function publish(router: Router, auth: IAuth, storage: IStorageHa router.delete('/:package/-rev/*', can('unpublish'), unPublishPackage(storage)); // 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) + ); // uploading package tarball - router.put('/:package/-/:filename/*', can('publish'), media(HEADERS.OCTET_STREAM), uploadPackageTarball(storage)); + router.put( + '/:package/-/:filename/*', + can('publish'), + media(HEADERS.OCTET_STREAM), + uploadPackageTarball(storage) + ); // adding a version - router.put('/:package/:version/-tag/:tag', can('publish'), media(mime.getType('json')), expectJson, addVersion(storage)); + router.put( + '/:package/:version/-tag/:tag', + can('publish'), + media(mime.getType('json')), + expectJson, + addVersion(storage) + ); } /** @@ -103,20 +142,20 @@ export default function publish(router: Router, auth: IAuth, storage: IStorageHa */ export function publishPackage(storage: IStorageHandler, config: Config, auth: IAuth): any { const starApi = star(storage); - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { const packageName = req.params.package; - logger.debug({packageName} , `publishing or updating a new version for @{packageName}`); + logger.debug({ packageName }, `publishing or updating a new version for @{packageName}`); /** * Write tarball of stream data from package clients. */ - const createTarball = function(filename: string, data, cb: Callback): void { + const createTarball = function (filename: string, data, cb: Callback): void { const stream = storage.addTarball(packageName, filename); - stream.on('error', function(err) { + stream.on('error', function (err) { cb(err); }); - stream.on('success', function() { + stream.on('success', function () { cb(); }); // this is dumb and memory-consuming, but what choices do we have? @@ -128,18 +167,18 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I /** * Add new package version in storage */ - const createVersion = function(version: string, metadata: Version, cb: Callback): void { + const createVersion = function (version: string, metadata: Version, cb: Callback): void { storage.addVersion(packageName, version, metadata, null, cb); }; /** * Add new tags in storage */ - const addTags = function(tags: MergeTags, cb: Callback): void { + const addTags = function (tags: MergeTags, cb: Callback): void { storage.mergeTags(packageName, tags, cb); }; - const afterChange = function(error, okMessage, metadata): void { + const afterChange = function (error, okMessage, metadata): void { const metadataCopy: Package = { ...metadata }; const { _attachments, versions } = metadataCopy; @@ -153,15 +192,18 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I res.status(HTTP_STATUS.CREATED); return next({ ok: okMessage, - success: true, + success: true }); } // npm-registry-client 0.3+ embeds tarball into the json upload // https://github.com/isaacs/npm-registry-client/commit/e9fbeb8b67f249394f735c74ef11fe4720d46ca0 // issue https://github.com/rlidwka/sinopia/issues/31, dealing with it here: - const isInvalidBodyFormat = isObject(_attachments) === false || hasDiffOneKey(_attachments) || - isObject(versions) === false || hasDiffOneKey(versions); + const isInvalidBodyFormat = + isObject(_attachments) === false || + hasDiffOneKey(_attachments) || + isObject(versions) === false || + hasDiffOneKey(versions); if (isInvalidBodyFormat) { // npm is doing something strange again @@ -177,37 +219,49 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I // at this point document is either created or existed before const [firstAttachmentKey] = Object.keys(_attachments); - createTarball(Path.basename(firstAttachmentKey), _attachments[firstAttachmentKey], function(error) { - if (error) { - return next(error); - } - - const versionToPublish = Object.keys(versions)[0]; - const versionMetadataToPublish = versions[versionToPublish]; - - versionMetadataToPublish.readme = _.isNil(versionMetadataToPublish.readme) === false ? String(versionMetadataToPublish.readme) : ''; - - createVersion(versionToPublish, versionMetadataToPublish, function(error) { + createTarball( + Path.basename(firstAttachmentKey), + _attachments[firstAttachmentKey], + function (error) { if (error) { return next(error); } - addTags(metadataCopy[DIST_TAGS], async function(error) { + const versionToPublish = Object.keys(versions)[0]; + const versionMetadataToPublish = versions[versionToPublish]; + + versionMetadataToPublish.readme = + _.isNil(versionMetadataToPublish.readme) === false + ? String(versionMetadataToPublish.readme) + : ''; + + createVersion(versionToPublish, versionMetadataToPublish, function (error) { if (error) { return next(error); } - try { - await notify(metadataCopy, config, req.remote_user, `${metadataCopy.name}@${versionToPublish}`); - } catch (error) { - logger.error({ error }, 'notify batch service has failed: @{error}'); - } + addTags(metadataCopy[DIST_TAGS], async function (error) { + if (error) { + return next(error); + } - res.status(HTTP_STATUS.CREATED); - return next({ ok: okMessage, success: true }); + try { + await notify( + metadataCopy, + config, + req.remote_user, + `${metadataCopy.name}@${versionToPublish}` + ); + } catch (error) { + logger.error({ error }, 'notify batch service has failed: @{error}'); + } + + res.status(HTTP_STATUS.CREATED); + return next({ ok: okMessage, success: true }); + }); }); - }); - }); + } + ); }; if (isPublishablePackage(req.body) === false && isObject(req.body.users)) { @@ -218,27 +272,27 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I const metadata = validateMetadata(req.body, packageName); // treating deprecation as updating a package if (req.params._rev || isRelatedToDeprecation(req.body)) { - logger.debug({packageName} , `updating a new version for @{packageName}`); + logger.debug({ packageName }, `updating a new version for @{packageName}`); // we check unpublish permissions, an update is basically remove versions const remote = req.remote_user; - auth.allow_unpublish({packageName}, remote, (error) => { + auth.allow_unpublish({ packageName }, remote, (error) => { if (error) { - logger.debug({packageName} , `not allowed to unpublish a version for @{packageName}`); + logger.debug({ packageName }, `not allowed to unpublish a version for @{packageName}`); return next(error); } - storage.changePackage(packageName, metadata, req.params.revision, function(error) { + storage.changePackage(packageName, metadata, req.params.revision, function (error) { afterChange(error, API_MESSAGE.PKG_CHANGED, metadata); }); }); } else { - logger.debug({packageName} , `adding a new version for @{packageName}`); - storage.addPackage(packageName, metadata, function(error) { + logger.debug({ packageName }, `adding a new version for @{packageName}`); + storage.addPackage(packageName, metadata, function (error) { afterChange(error, API_MESSAGE.PKG_CREATED, metadata); }); } } catch (error) { - logger.error({packageName}, 'error on publish, bad package data for @{packageName}'); + logger.error({ packageName }, 'error on publish, bad package data for @{packageName}'); return next(ErrorCode.getBadData(API_ERROR.BAD_PACKAGE_DATA)); } }; @@ -248,11 +302,11 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I * un-publish a package */ export function unPublishPackage(storage: IStorageHandler) { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { const packageName = req.params.package; - logger.debug({packageName} , `unpublishing @{packageName}`); - storage.removePackage(packageName, function(err) { + logger.debug({ packageName }, `unpublishing @{packageName}`); + storage.removePackage(packageName, function (err) { if (err) { return next(err); } @@ -266,18 +320,24 @@ export function unPublishPackage(storage: IStorageHandler) { * Delete tarball */ export function removeTarball(storage: IStorageHandler) { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { const packageName = req.params.package; - const {filename, revision} = req.params; + const { filename, revision } = req.params; - logger.debug({packageName, filename, revision} , `removing a tarball for @{packageName}-@{tarballName}-@{revision}`); - storage.removeTarball(packageName, filename, revision, function(err) { + logger.debug( + { packageName, filename, revision }, + `removing a tarball for @{packageName}-@{tarballName}-@{revision}` + ); + storage.removeTarball(packageName, filename, revision, function (err) { if (err) { return next(err); } res.status(HTTP_STATUS.CREATED); - logger.debug({packageName, filename, revision} , `success remove tarball for @{packageName}-@{tarballName}-@{revision}`); + logger.debug( + { packageName, filename, revision }, + `success remove tarball for @{packageName}-@{tarballName}-@{revision}` + ); return next({ ok: API_MESSAGE.TARBALL_REMOVED }); }); }; @@ -286,18 +346,18 @@ export function removeTarball(storage: IStorageHandler) { * Adds a new version */ export function addVersion(storage: IStorageHandler) { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { const { version, tag } = req.params; const packageName = req.params.package; - storage.addVersion(packageName, version, req.body, tag, function(error) { + storage.addVersion(packageName, version, req.body, tag, function (error) { if (error) { return next(error); } res.status(HTTP_STATUS.CREATED); return next({ - ok: API_MESSAGE.PKG_PUBLISHED, + ok: API_MESSAGE.PKG_PUBLISHED }); }); }; @@ -307,32 +367,32 @@ export function addVersion(storage: IStorageHandler) { * uploadPackageTarball */ export function uploadPackageTarball(storage: IStorageHandler) { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { const packageName = req.params.package; const stream = storage.addTarball(packageName, req.params.filename); req.pipe(stream); // checking if end event came before closing let complete = false; - req.on('end', function() { + req.on('end', function () { complete = true; stream.done(); }); - req.on('close', function() { + req.on('close', function () { if (!complete) { stream.abort(); } }); - stream.on('error', function(err) { + stream.on('error', function (err) { return res.report_error(err); }); - stream.on('success', function() { + stream.on('success', function () { res.status(HTTP_STATUS.CREATED); return next({ - ok: API_MESSAGE.TARBALL_UPLOADED, + ok: API_MESSAGE.TARBALL_UPLOADED }); }); }; diff --git a/src/api/endpoint/api/search.ts b/src/api/endpoint/api/search.ts index 22eb4b476..a2ef24bcc 100644 --- a/src/api/endpoint/api/search.ts +++ b/src/api/endpoint/api/search.ts @@ -1,19 +1,19 @@ -import { HEADERS } from "../../../lib/constants"; +import { HEADERS } from '../../../lib/constants'; /** * @prettier */ -export default function(route, auth, storage): void { +export default function (route, auth, storage): void { // searching packages - route.get('/-/all(/since)?', function(req, res) { + route.get('/-/all(/since)?', function (req, res) { let received_end = false; let response_finished = false; let processing_pkgs = 0; let firstPackage = true; res.status(200); - res.set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET) + res.set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET); /* * Offical NPM registry (registry.npmjs.org) no longer return whole database, @@ -34,8 +34,10 @@ export default function(route, auth, storage): void { * when request /-/all/since, response is an array */ const respShouldBeArray = req.path.endsWith('/since'); - if (!respShouldBeArray) res.set('Date', 'Mon, 10 Oct 1983 00:12:48 GMT'); - const check_finish = function(): void { + if (!respShouldBeArray) { + res.set('Date', 'Mon, 10 Oct 1983 00:12:48 GMT'); + } + const check_finish = function (): void { if (!received_end) { return; } @@ -64,7 +66,7 @@ export default function(route, auth, storage): void { stream.on('data', function each(pkg) { processing_pkgs++; - auth.allow_access({ packageName: pkg.name }, req.remote_user, function(err, allowed) { + auth.allow_access({ packageName: pkg.name }, req.remote_user, function (err, allowed) { processing_pkgs--; if (err) { @@ -92,11 +94,11 @@ export default function(route, auth, storage): void { }); }); - stream.on('error', function() { + stream.on('error', function () { res.socket.destroy(); }); - stream.on('end', function() { + stream.on('end', function () { received_end = true; check_finish(); }); diff --git a/src/api/endpoint/api/star.ts b/src/api/endpoint/api/star.ts index f41436699..e3ad24260 100644 --- a/src/api/endpoint/api/star.ts +++ b/src/api/endpoint/api/star.ts @@ -1,12 +1,14 @@ // @flow -import { USERS, HTTP_STATUS } from '../../../lib/constants'; -import {Response} from 'express'; -import {$RequestExtend, $NextFunctionVer, IStorageHandler} from '../../../../types'; +import { Response } from 'express'; import _ from 'lodash'; +import { USERS, HTTP_STATUS } from '../../../lib/constants'; +import { $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types'; import { logger } from '../../../lib/logger'; -export default function(storage: IStorageHandler): (req: $RequestExtend, res: Response, next: $NextFunctionVer) => void { +export default function ( + storage: IStorageHandler +): (req: $RequestExtend, res: Response, next: $NextFunctionVer) => void { const validateInputs = (newUsers, localUsers, username, isStar): boolean => { const isExistlocalUsers = _.isNil(localUsers[username]) === false; if (isStar && isExistlocalUsers && localUsers[username]) { @@ -21,21 +23,21 @@ export default function(storage: IStorageHandler): (req: $RequestExtend, res: Re return (req: $RequestExtend, res: Response, next: $NextFunctionVer): void => { const name = req.params.package; - logger.debug({name}, 'starring a package for @{name}'); - const afterChangePackage = function(err?: Error) { + logger.debug({ name }, 'starring a package for @{name}'); + const afterChangePackage = function (err?: Error) { if (err) { return next(err); } res.status(HTTP_STATUS.OK); next({ - success: true, + success: true }); }; storage.getPackage({ name, req, - callback: function(err, info) { + callback: function (err, info) { if (err) { return next(err); } @@ -44,22 +46,31 @@ export default function(storage: IStorageHandler): (req: $RequestExtend, res: Re const localStarUsers = info[USERS]; // Check is star or unstar const isStar = Object.keys(newStarUser).includes(remoteUsername); - if (_.isNil(localStarUsers) === false && validateInputs(newStarUser, localStarUsers, remoteUsername, isStar)) { + if ( + _.isNil(localStarUsers) === false && + validateInputs(newStarUser, localStarUsers, remoteUsername, isStar) + ) { return afterChangePackage(); } - const users = isStar ? { - ...localStarUsers, - [remoteUsername]: true, - } : _.reduce(localStarUsers, (users, value, key) => { - if (key !== remoteUsername) { - users[key] = value; - } - return users; - }, {}); - storage.changePackage(name, { ...info, users}, req.body._rev, function(err) { + const users = isStar + ? { + ...localStarUsers, + [remoteUsername]: true + } + : _.reduce( + localStarUsers, + (users, value, key) => { + if (key !== remoteUsername) { + users[key] = value; + } + return users; + }, + {} + ); + storage.changePackage(name, { ...info, users }, req.body._rev, function (err) { afterChangePackage(err); }); - }, + } }); }; } diff --git a/src/api/endpoint/api/stars.ts b/src/api/endpoint/api/stars.ts index db56e8dd4..c01cece5e 100644 --- a/src/api/endpoint/api/stars.ts +++ b/src/api/endpoint/api/stars.ts @@ -3,32 +3,35 @@ */ import _ from 'lodash'; -import { USERS, HTTP_STATUS } from '../../../lib/constants'; import { Response, Router } from 'express'; -import { $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types'; import { Package } from '@verdaccio/types'; +import { USERS, HTTP_STATUS } from '../../../lib/constants'; +import { $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types'; type Packages = Package[]; -export default function(route: Router, storage: IStorageHandler): void { - route.get('/-/_view/starredByUser', (req: $RequestExtend, res: Response, next: $NextFunctionVer): void => { - const remoteUsername = req.remote_user.name; +export default function (route: Router, storage: IStorageHandler): void { + route.get( + '/-/_view/starredByUser', + (req: $RequestExtend, res: Response, next: $NextFunctionVer): void => { + const remoteUsername = req.remote_user.name; - storage.getLocalDatabase((err, localPackages: Packages) => { - if (err) { - return next(err); - } + storage.getLocalDatabase((err, localPackages: Packages) => { + if (err) { + return next(err); + } - const filteredPackages: Packages = localPackages.filter((localPackage: Package) => - _.keys(localPackage[USERS]).includes(remoteUsername) - ); + const filteredPackages: Packages = localPackages.filter((localPackage: Package) => + _.keys(localPackage[USERS]).includes(remoteUsername) + ); - res.status(HTTP_STATUS.OK); - next({ - rows: filteredPackages.map((filteredPackage: Package) => ({ - value: filteredPackage.name, - })), + res.status(HTTP_STATUS.OK); + next({ + rows: filteredPackages.map((filteredPackage: Package) => ({ + value: filteredPackage.name + })) + }); }); - }); - }); + } + ); } diff --git a/src/api/endpoint/api/user.ts b/src/api/endpoint/api/user.ts index f4bc6d58e..fca83dd8b 100644 --- a/src/api/endpoint/api/user.ts +++ b/src/api/endpoint/api/user.ts @@ -1,89 +1,120 @@ import _ from 'lodash'; import Cookies from 'cookies'; -import { ErrorCode } from '../../../lib/utils'; -import { API_ERROR, API_MESSAGE, HTTP_STATUS } from '../../../lib/constants'; -import { createRemoteUser, createSessionToken, getApiToken, getAuthenticatedMessage, validatePassword } from '../../../lib/auth-utils'; -import { logger } from '../../../lib/logger'; - import { Config, RemoteUser } from '@verdaccio/types'; import { Response, Router } from 'express'; +import { ErrorCode } from '../../../lib/utils'; +import { API_ERROR, API_MESSAGE, HTTP_STATUS } from '../../../lib/constants'; +import { + createRemoteUser, + createSessionToken, + getApiToken, + getAuthenticatedMessage, + validatePassword +} from '../../../lib/auth-utils'; +import { logger } from '../../../lib/logger'; + import { $RequestExtend, $ResponseExtend, $NextFunctionVer, IAuth } from '../../../../types'; -export default function(route: Router, auth: IAuth, config: Config): void { - route.get('/-/user/:org_couchdb_user', function(req: $RequestExtend, res: Response, next: $NextFunctionVer): void { - res.status(HTTP_STATUS.OK); - next({ - ok: getAuthenticatedMessage(req.remote_user.name), - }); - }); - - route.put('/-/user/:org_couchdb_user/:_rev?/:revision?', function(req: $RequestExtend, res: Response, next: $NextFunctionVer): void { - const { name, password } = req.body; - const remoteName = req.remote_user.name; - - if (_.isNil(remoteName) === false && _.isNil(name) === false && remoteName === name) { - auth.authenticate(name, password, async function callbackAuthenticate(err, user): Promise { - if (err) { - logger.trace({ name, err }, 'authenticating for user @{username} failed. Error: @{err.message}'); - return next(ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.BAD_USERNAME_PASSWORD)); - } - - const restoredRemoteUser: RemoteUser = createRemoteUser(name, user.groups || []); - const token = await getApiToken(auth, config, restoredRemoteUser, password); - - res.status(HTTP_STATUS.CREATED); - - return next({ - ok: getAuthenticatedMessage(req.remote_user.name), - token, - }); - }); - } else { - if (validatePassword(password) === false) { - // eslint-disable-next-line new-cap - return next(ErrorCode.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT())); - } - - auth.add_user(name, password, async function(err, user): Promise { - if (err) { - if (err.status >= HTTP_STATUS.BAD_REQUEST && err.status < HTTP_STATUS.INTERNAL_ERROR) { - // With npm registering is the same as logging in, - // and npm accepts only an 409 error. - // So, changing status code here. - return next(ErrorCode.getCode(err.status, err.message) || ErrorCode.getConflict(err.message)); - } - return next(err); - } - - const token = name && password ? await getApiToken(auth, config, user, password) : undefined; - - req.remote_user = user; - res.status(HTTP_STATUS.CREATED); - return next({ - ok: `user '${req.body.name}' created`, - token, - }); +export default function (route: Router, auth: IAuth, config: Config): void { + route.get( + '/-/user/:org_couchdb_user', + function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void { + res.status(HTTP_STATUS.OK); + next({ + ok: getAuthenticatedMessage(req.remote_user.name) }); } - }); + ); - route.delete('/-/user/token/*', function(req: $RequestExtend, res: Response, next: $NextFunctionVer): void { - res.status(HTTP_STATUS.OK); - next({ - ok: API_MESSAGE.LOGGED_OUT, - }); - }); + route.put( + '/-/user/:org_couchdb_user/:_rev?/:revision?', + function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void { + const { name, password } = req.body; + const remoteName = req.remote_user.name; + + if (_.isNil(remoteName) === false && _.isNil(name) === false && remoteName === name) { + auth.authenticate( + name, + password, + async function callbackAuthenticate(err, user): Promise { + if (err) { + logger.trace( + { name, err }, + 'authenticating for user @{username} failed. Error: @{err.message}' + ); + return next( + ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.BAD_USERNAME_PASSWORD) + ); + } + + const restoredRemoteUser: RemoteUser = createRemoteUser(name, user.groups || []); + const token = await getApiToken(auth, config, restoredRemoteUser, password); + + res.status(HTTP_STATUS.CREATED); + + return next({ + ok: getAuthenticatedMessage(req.remote_user.name), + token + }); + } + ); + } else { + if (validatePassword(password) === false) { + // eslint-disable-next-line new-cap + return next(ErrorCode.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT())); + } + + auth.add_user(name, password, async function (err, user): Promise { + if (err) { + if (err.status >= HTTP_STATUS.BAD_REQUEST && err.status < HTTP_STATUS.INTERNAL_ERROR) { + // With npm registering is the same as logging in, + // and npm accepts only an 409 error. + // So, changing status code here. + return next( + ErrorCode.getCode(err.status, err.message) || ErrorCode.getConflict(err.message) + ); + } + return next(err); + } + + const token = + name && password ? await getApiToken(auth, config, user, password) : undefined; + + req.remote_user = user; + res.status(HTTP_STATUS.CREATED); + return next({ + ok: `user '${req.body.name}' created`, + token + }); + }); + } + } + ); + + route.delete( + '/-/user/token/*', + function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void { + res.status(HTTP_STATUS.OK); + next({ + ok: API_MESSAGE.LOGGED_OUT + }); + } + ); // placeholder 'cause npm require to be authenticated to publish // we do not do any real authentication yet - route.post('/_session', Cookies.express(), function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - res.cookies.set('AuthSession', String(Math.random()), createSessionToken()); + route.post( + '/_session', + Cookies.express(), + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + res.cookies.set('AuthSession', String(Math.random()), createSessionToken()); - next({ - ok: true, - name: 'somebody', - roles: [], - }); - }); + next({ + ok: true, + name: 'somebody', + roles: [] + }); + } + ); } diff --git a/src/api/endpoint/api/v1/profile.ts b/src/api/endpoint/api/v1/profile.ts index 200b7dc21..887d1afe0 100644 --- a/src/api/endpoint/api/v1/profile.ts +++ b/src/api/endpoint/api/v1/profile.ts @@ -1,9 +1,9 @@ import _ from 'lodash'; +import { Response, Router } from 'express'; import { API_ERROR, APP_ERROR, HTTP_STATUS, SUPPORT_ERRORS } from '../../../../lib/constants'; import { ErrorCode } from '../../../../lib/utils'; import { validatePassword } from '../../../../lib/auth-utils'; -import { Response, Router } from 'express'; import { $NextFunctionVer, $RequestExtend, IAuth } from '../../../../../types'; export interface Profile { @@ -17,7 +17,7 @@ export interface Profile { fullname: string; } -export default function(route: Router, auth: IAuth): void { +export default function (route: Router, auth: IAuth): void { function buildProfile(name: string): Profile { return { tfa: false, @@ -27,58 +27,68 @@ export default function(route: Router, auth: IAuth): void { created: '', updated: '', cidr_whitelist: null, - fullname: '', + fullname: '' }; } - route.get('/-/npm/v1/user', function(req: $RequestExtend, res: Response, next: $NextFunctionVer): void { - if (_.isNil(req.remote_user.name) === false) { - return next(buildProfile(req.remote_user.name)); - } - - res.status(HTTP_STATUS.UNAUTHORIZED); - return next({ - message: API_ERROR.MUST_BE_LOGGED, - }); - }); - - route.post('/-/npm/v1/user', function(req: $RequestExtend, res: Response, next: $NextFunctionVer): void { - if (_.isNil(req.remote_user.name)) { - res.status(HTTP_STATUS.UNAUTHORIZED); - return next({ - message: API_ERROR.MUST_BE_LOGGED, - }); - } - - const { password, tfa } = req.body; - const { name } = req.remote_user; - - if (_.isNil(password) === false) { - if (validatePassword(password.new) === false) { - /* eslint new-cap:off */ - return next(ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT())); - /* eslint new-cap:off */ + route.get( + '/-/npm/v1/user', + function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void { + if (_.isNil(req.remote_user.name) === false) { + return next(buildProfile(req.remote_user.name)); } - auth.changePassword( - name, - password.old, - password.new, - (err, isUpdated): $NextFunctionVer => { - if (_.isNull(err) === false) { - return next(ErrorCode.getCode(err.status, err.message) || ErrorCode.getConflict(err.message)); - } - - if (isUpdated) { - return next(buildProfile(req.remote_user.name)); - } - return next(ErrorCode.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR)); - } - ); - } else if (_.isNil(tfa) === false) { - return next(ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.TFA_DISABLED)); - } else { - return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, APP_ERROR.PROFILE_ERROR)); + res.status(HTTP_STATUS.UNAUTHORIZED); + return next({ + message: API_ERROR.MUST_BE_LOGGED + }); } - }); + ); + + route.post( + '/-/npm/v1/user', + function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void { + if (_.isNil(req.remote_user.name)) { + res.status(HTTP_STATUS.UNAUTHORIZED); + return next({ + message: API_ERROR.MUST_BE_LOGGED + }); + } + + const { password, tfa } = req.body; + const { name } = req.remote_user; + + if (_.isNil(password) === false) { + if (validatePassword(password.new) === false) { + /* eslint new-cap:off */ + return next(ErrorCode.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT())); + /* eslint new-cap:off */ + } + + auth.changePassword( + name, + password.old, + password.new, + (err, isUpdated): $NextFunctionVer => { + if (_.isNull(err) === false) { + return next( + ErrorCode.getCode(err.status, err.message) || ErrorCode.getConflict(err.message) + ); + } + + if (isUpdated) { + return next(buildProfile(req.remote_user.name)); + } + return next(ErrorCode.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR)); + } + ); + } else if (_.isNil(tfa) === false) { + return next( + ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.TFA_DISABLED) + ); + } else { + return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, APP_ERROR.PROFILE_ERROR)); + } + } + ); } diff --git a/src/api/endpoint/api/v1/search.ts b/src/api/endpoint/api/v1/search.ts index 70f491d6a..539a56e18 100644 --- a/src/api/endpoint/api/v1/search.ts +++ b/src/api/endpoint/api/v1/search.ts @@ -1,98 +1,105 @@ -import semver from 'semver' +import semver from 'semver'; import { Package } from '@verdaccio/types'; -function compileTextSearch(textSearch: string): ((pkg: Package) => boolean) { - const personMatch = (person, search) => { - if(typeof person === 'string') - return person.includes(search); - - if(typeof person === 'object') - for(const field of Object.values(person)) - if(typeof field === 'string' && field.includes(search)) - return true; - - return false; - } - const matcher = function(q) { - const match = q.match(/author:(.*)/) - if(match !== null) - return (pkg) => personMatch(pkg.author, match[1]) +function compileTextSearch(textSearch: string): (pkg: Package) => boolean { + const personMatch = (person, search) => { + if (typeof person === 'string') { + return person.includes(search); + } - // TODO: maintainer, keywords, not/is unstable insecure, boost-exact - // TODO implement some scoring system for freetext - return (pkg) => { - return ['name', 'displayName', 'description'] - .map(k => pkg[k]) - .filter(x => x !== undefined) - .some(txt => txt.includes(q)) - }; + if (typeof person === 'object') { + for (const field of Object.values(person)) { + if (typeof field === 'string' && field.includes(search)) { + return true; } + } + } - const textMatchers = (textSearch || '').split(' ').map(matcher); - return (pkg) => textMatchers.every(m => m(pkg)); + return false; + }; + const matcher = function (q) { + const match = q.match(/author:(.*)/); + if (match !== null) { + return (pkg) => personMatch(pkg.author, match[1]); + } + + // TODO: maintainer, keywords, not/is unstable insecure, boost-exact + // TODO implement some scoring system for freetext + return (pkg) => { + return ['name', 'displayName', 'description'] + .map((k) => pkg[k]) + .filter((x) => x !== undefined) + .some((txt) => txt.includes(q)); + }; + }; + + const textMatchers = (textSearch || '').split(' ').map(matcher); + return (pkg) => textMatchers.every((m) => m(pkg)); } -export default function(route, auth, storage): void { - route.get('/-/v1/search', (req, res)=>{ - // TODO: implement proper result scoring weighted by quality, popularity and maintenance query parameters - let [text, size, from /* , quality, popularity, maintenance */] = - ['text', 'size', 'from' /* , 'quality', 'popularity', 'maintenance' */] - .map(k => req.query[k]) - - size = parseInt(size) || 20; - from = parseInt(from) || 0; - - const isInteresting = compileTextSearch(text); +export default function (route, auth, storage): void { + route.get('/-/v1/search', (req, res) => { + // TODO: implement proper result scoring weighted by quality, popularity and maintenance query parameters + let [text, size, from /* , quality, popularity, maintenance */] = [ + 'text', + 'size', + 'from' /* , 'quality', 'popularity', 'maintenance' */ + ].map((k) => req.query[k]); - const resultStream = storage.search(0, {req: {query: {local: true}}}); - const resultBuf = [] as any; - let completed = false; + size = parseInt(size) || 20; + from = parseInt(from) || 0; - const sendResponse = (): void => { - completed = true; - resultStream.destroy() + const isInteresting = compileTextSearch(text); - const final = resultBuf.slice(from, size).map(pkg => { - return { - package: pkg, - flags: { - unstable: - Object.keys(pkg.versions) - .some(v => semver.satisfies(v, '^1.0.0')) - ? undefined - : true - }, - score: { - final: 1, - detail: { - quality: 1, - popularity: 1, - maintenance: 0 - } - }, - searchScore: 100000 - } - }) - const response = { - objects: final, - total: final.length, - time: new Date().toUTCString() - } + const resultStream = storage.search(0, { req: { query: { local: true } } }); + const resultBuf = [] as any; + let completed = false; - res.status(200) - .json(response) - } + const sendResponse = (): void => { + completed = true; + resultStream.destroy(); - resultStream.on('data', (pkg)=>{ - if(!isInteresting(pkg)) - return; - resultBuf.push(pkg) - if(!completed && resultBuf.length >= size + from) - sendResponse(); - }) - resultStream.on('end', ()=>{ - if(!completed) - sendResponse() - }) - }) -} \ No newline at end of file + const final = resultBuf.slice(from, size).map((pkg) => { + return { + package: pkg, + flags: { + unstable: Object.keys(pkg.versions).some((v) => semver.satisfies(v, '^1.0.0')) + ? undefined + : true + }, + score: { + final: 1, + detail: { + quality: 1, + popularity: 1, + maintenance: 0 + } + }, + searchScore: 100000 + }; + }); + const response = { + objects: final, + total: final.length, + time: new Date().toUTCString() + }; + + res.status(200).json(response); + }; + + resultStream.on('data', (pkg) => { + if (!isInteresting(pkg)) { + return; + } + resultBuf.push(pkg); + if (!completed && resultBuf.length >= size + from) { + sendResponse(); + } + }); + resultStream.on('end', () => { + if (!completed) { + sendResponse(); + } + }); + }); +} diff --git a/src/api/endpoint/api/v1/token.ts b/src/api/endpoint/api/v1/token.ts index c4eb1debd..354b1e926 100644 --- a/src/api/endpoint/api/v1/token.ts +++ b/src/api/endpoint/api/v1/token.ts @@ -1,123 +1,143 @@ import _ from 'lodash'; +import { Response, Router } from 'express'; +import { Config, RemoteUser, Token } from '@verdaccio/types'; import { HTTP_STATUS, SUPPORT_ERRORS } from '../../../../lib/constants'; -import {ErrorCode, mask} from '../../../../lib/utils'; +import { ErrorCode, mask } from '../../../../lib/utils'; import { getApiToken } from '../../../../lib/auth-utils'; import { stringToMD5 } from '../../../../lib/crypto-utils'; import { logger } from '../../../../lib/logger'; -import { Response, Router } from 'express'; -import {$NextFunctionVer, $RequestExtend, IAuth, IStorageHandler} from '../../../../../types'; -import { Config, RemoteUser, Token } from '@verdaccio/types'; +import { $NextFunctionVer, $RequestExtend, IAuth, IStorageHandler } from '../../../../../types'; export type NormalizeToken = Token & { - created: string; + created: string; }; function normalizeToken(token: Token): NormalizeToken { - return { - ...token, - created: new Date(token.created).toISOString(), - }; -}; + return { + ...token, + created: new Date(token.created).toISOString() + }; +} // https://github.com/npm/npm-profile/blob/latest/lib/index.js -export default function(route: Router, auth: IAuth, storage: IStorageHandler, config: Config): void { - route.get('/-/npm/v1/tokens', async function(req: $RequestExtend, res: Response, next: $NextFunctionVer) { - const { name } = req.remote_user; +export default function ( + route: Router, + auth: IAuth, + storage: IStorageHandler, + config: Config +): void { + route.get( + '/-/npm/v1/tokens', + async function (req: $RequestExtend, res: Response, next: $NextFunctionVer) { + const { name } = req.remote_user; - if (_.isNil(name) === false) { - try { - const tokens = await storage.readTokens({user: name}); - const totalTokens = tokens.length; - logger.debug({totalTokens}, 'token list retrieved: @{totalTokens}'); + if (_.isNil(name) === false) { + try { + const tokens = await storage.readTokens({ user: name }); + const totalTokens = tokens.length; + logger.debug({ totalTokens }, 'token list retrieved: @{totalTokens}'); - res.status(HTTP_STATUS.OK); - return next({ - objects: tokens.map(normalizeToken), - urls: { - next: '', // TODO: pagination? - }, - }); - } catch (error) { - logger.error({ error: error.msg }, 'token list has failed: @{error}'); - return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message)); - } - } - return next(ErrorCode.getUnauthorized()); - }); + res.status(HTTP_STATUS.OK); + return next({ + objects: tokens.map(normalizeToken), + urls: { + next: '' // TODO: pagination? + } + }); + } catch (error) { + logger.error({ error: error.msg }, 'token list has failed: @{error}'); + return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message)); + } + } + return next(ErrorCode.getUnauthorized()); + } + ); - route.post('/-/npm/v1/tokens', function(req: $RequestExtend, res: Response, next: $NextFunctionVer) { - const { password, readonly, cidr_whitelist } = req.body; - const { name } = req.remote_user; + route.post( + '/-/npm/v1/tokens', + function (req: $RequestExtend, res: Response, next: $NextFunctionVer) { + const { password, readonly, cidr_whitelist } = req.body; + const { name } = req.remote_user; - if (!_.isBoolean(readonly) || !_.isArray(cidr_whitelist)) { - return next(ErrorCode.getCode(HTTP_STATUS.BAD_DATA, SUPPORT_ERRORS.PARAMETERS_NOT_VALID)); - } + if (!_.isBoolean(readonly) || !_.isArray(cidr_whitelist)) { + return next(ErrorCode.getCode(HTTP_STATUS.BAD_DATA, SUPPORT_ERRORS.PARAMETERS_NOT_VALID)); + } - auth.authenticate(name, password, async (err, user: RemoteUser) => { - if (err) { - const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR; - return next(ErrorCode.getCode(errorCode, err.message)); - } + auth.authenticate(name, password, async (err, user: RemoteUser) => { + if (err) { + const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR; + return next(ErrorCode.getCode(errorCode, err.message)); + } - req.remote_user = user; + req.remote_user = user; - if (!_.isFunction(storage.saveToken)) { - return next(ErrorCode.getCode(HTTP_STATUS.NOT_IMPLEMENTED, SUPPORT_ERRORS.STORAGE_NOT_IMPLEMENT)); - } + if (!_.isFunction(storage.saveToken)) { + return next( + ErrorCode.getCode(HTTP_STATUS.NOT_IMPLEMENTED, SUPPORT_ERRORS.STORAGE_NOT_IMPLEMENT) + ); + } - try { - const token = await getApiToken(auth, config, user, password); - const key = stringToMD5(token); - // TODO: use a utility here - const maskedToken = mask(token, 5); - const created = new Date().getTime(); + try { + const token = await getApiToken(auth, config, user, password); + const key = stringToMD5(token); + // TODO: use a utility here + const maskedToken = mask(token, 5); + const created = new Date().getTime(); - /** - * cidr_whitelist: is not being used, we pass it through - * token: we do not store the real token (it is generated once and retrieved to the user), just a mask of it. - */ - const saveToken: Token = { - user: name, - token: maskedToken, - key, - cidr: cidr_whitelist, - readonly, - created, - }; + /** + * cidr_whitelist: is not being used, we pass it through + * token: we do not store the real token (it is generated once and retrieved to the user), just a mask of it. + */ + const saveToken: Token = { + user: name, + token: maskedToken, + key, + cidr: cidr_whitelist, + readonly, + created + }; - await storage.saveToken(saveToken); - logger.debug({ key, name }, 'token @{key} was created for user @{name}'); - return next(normalizeToken({ - token, - user: name, - key: saveToken.key, - cidr: cidr_whitelist, - readonly, - created: saveToken.created, - })); - } catch (error) { - logger.error({ error: error.msg }, 'token creation has failed: @{error}'); - return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message)); - } - }); - }); + await storage.saveToken(saveToken); + logger.debug({ key, name }, 'token @{key} was created for user @{name}'); + return next( + normalizeToken({ + token, + user: name, + key: saveToken.key, + cidr: cidr_whitelist, + readonly, + created: saveToken.created + }) + ); + } catch (error) { + logger.error({ error: error.msg }, 'token creation has failed: @{error}'); + return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message)); + } + }); + } + ); - route.delete('/-/npm/v1/tokens/token/:tokenKey', async (req: $RequestExtend, res: Response, next: $NextFunctionVer) => { - const { params: { tokenKey }} = req; - const { name } = req.remote_user; + route.delete( + '/-/npm/v1/tokens/token/:tokenKey', + async (req: $RequestExtend, res: Response, next: $NextFunctionVer) => { + const { + params: { tokenKey } + } = req; + const { name } = req.remote_user; - if (_.isNil(name) === false) { - logger.debug({name}, '@{name} has requested remove a token'); - try { - await storage.deleteToken(name, tokenKey); - logger.info({ tokenKey, name }, 'token id @{tokenKey} was revoked for user @{name}'); - return next({}); - } catch(error) { - logger.error({ error: error.msg }, 'token creation has failed: @{error}'); - return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message)); - } - } - return next(ErrorCode.getUnauthorized()); - }); + if (_.isNil(name) === false) { + logger.debug({ name }, '@{name} has requested remove a token'); + try { + await storage.deleteToken(name, tokenKey); + logger.info({ tokenKey, name }, 'token id @{tokenKey} was revoked for user @{name}'); + return next({}); + } catch (error) { + logger.error({ error: error.msg }, 'token creation has failed: @{error}'); + return next(ErrorCode.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message)); + } + } + return next(ErrorCode.getUnauthorized()); + } + ); } diff --git a/src/api/endpoint/api/whoami.ts b/src/api/endpoint/api/whoami.ts index d36b31f61..e84b18e94 100644 --- a/src/api/endpoint/api/whoami.ts +++ b/src/api/endpoint/api/whoami.ts @@ -1,22 +1,16 @@ import { Response, Router } from 'express'; import { $RequestExtend, $NextFunctionVer } from '../../../../types'; -export default function(route: Router): void { - route.get( - '/whoami', - (req: $RequestExtend, res: Response, next: $NextFunctionVer): void => { - if (req.headers.referer === 'whoami') { - next({ username: req.remote_user.name }); - } else { - next('route'); - } - } - ); - - route.get( - '/-/whoami', - (req: $RequestExtend, res: Response, next: $NextFunctionVer): any => { +export default function (route: Router): void { + route.get('/whoami', (req: $RequestExtend, res: Response, next: $NextFunctionVer): void => { + if (req.headers.referer === 'whoami') { next({ username: req.remote_user.name }); + } else { + next('route'); } - ); + }); + + route.get('/-/whoami', (req: $RequestExtend, res: Response, next: $NextFunctionVer): any => { + next({ username: req.remote_user.name }); + }); } diff --git a/src/api/endpoint/index.ts b/src/api/endpoint/index.ts index 73ff040ce..d317c4ba6 100644 --- a/src/api/endpoint/index.ts +++ b/src/api/endpoint/index.ts @@ -1,9 +1,9 @@ -import { IAuth, IStorageHandler } from '../../../types'; import { Config } from '@verdaccio/types'; import _ from 'lodash'; import express from 'express'; import bodyParser from 'body-parser'; +import { IAuth, IStorageHandler } from '../../../types'; import whoami from './api/whoami'; import ping from './api/ping'; import user from './api/user'; @@ -15,11 +15,17 @@ import stars from './api/stars'; import profile from './api/v1/profile'; import token from './api/v1/token'; -import v1Search from './api/v1/search' +import v1Search from './api/v1/search'; -const { match, validateName, validatePackage, encodeScopePackage, antiLoop } = require('../middleware'); +const { + match, + validateName, + validatePackage, + encodeScopePackage, + antiLoop +} = require('../middleware'); -export default function(config: Config, auth: IAuth, storage: IStorageHandler) { +export default function (config: Config, auth: IAuth, storage: IStorageHandler) { /* eslint new-cap:off */ const app = express.Router(); /* eslint new-cap:off */ @@ -58,7 +64,7 @@ export default function(config: Config, auth: IAuth, storage: IStorageHandler) { stars(app, storage); if (_.get(config, 'experiments.search') === true) { - v1Search(app, auth, storage) + v1Search(app, auth, storage); } if (_.get(config, 'experiments.token') === true) { diff --git a/src/api/index.ts b/src/api/index.ts index 6c26ea8d3..49bfc62bc 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -3,22 +3,28 @@ import express, { Application } from 'express'; import compression from 'compression'; import cors from 'cors'; import { HttpError } from 'http-errors'; +import { Config as IConfig, IPluginMiddleware, IPluginStorageFilter } from '@verdaccio/types'; import Storage from '../lib/storage'; import loadPlugin from '../lib/plugin-loader'; -import hookDebug from './debug'; import Auth from '../lib/auth'; -import apiEndpoint from './endpoint'; import { ErrorCode } from '../lib/utils'; import { API_ERROR, HTTP_STATUS } from '../lib/constants'; import AppConfig from '../lib/config'; +import { + $ResponseExtend, + $RequestExtend, + $NextFunctionVer, + IStorageHandler, + IAuth +} from '../../types'; +import { setup, logger } from '../lib/logger'; import webAPI from './web/api'; import web from './web'; -import { $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler, IAuth } from '../../types'; -import { Config as IConfig, IPluginMiddleware, IPluginStorageFilter } from '@verdaccio/types'; -import { setup, logger } from '../lib/logger'; +import apiEndpoint from './endpoint'; +import hookDebug from './debug'; import { log, final, errorReportingMiddleware } from './middleware'; -const defineAPI = function(config: IConfig, storage: IStorageHandler): any { +const defineAPI = function (config: IConfig, storage: IStorageHandler): any { const auth: IAuth = new Auth(config); const app: Application = express(); // run in production mode by default, just in case @@ -29,17 +35,20 @@ const defineAPI = function(config: IConfig, storage: IStorageHandler): any { // Router setup app.use(log(config)); app.use(errorReportingMiddleware); - app.use(function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + app.use(function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { res.setHeader('X-Powered-By', config.user_agent); next(); }); app.use(compression()); - app.get('/favicon.ico', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - req.url = '/-/static/favicon.png'; - next(); - }); + app.get( + '/favicon.ico', + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + req.url = '/-/static/favicon.png'; + next(); + } + ); // Hook for tests only if (config._debug) { @@ -49,12 +58,17 @@ const defineAPI = function(config: IConfig, storage: IStorageHandler): any { // register middleware plugins const plugin_params = { config: config, - logger: logger, + logger: logger }; - const plugins: IPluginMiddleware[] = loadPlugin(config, config.middlewares, plugin_params, function(plugin: IPluginMiddleware) { - return plugin.register_middlewares; - }); + const plugins: IPluginMiddleware[] = loadPlugin( + config, + config.middlewares, + plugin_params, + function (plugin: IPluginMiddleware) { + return plugin.register_middlewares; + } + ); plugins.forEach((plugin: IPluginMiddleware) => { plugin.register_middlewares(app, auth, storage); }); @@ -67,17 +81,22 @@ const defineAPI = function(config: IConfig, storage: IStorageHandler): any { app.use('/', web(config, auth, storage)); app.use('/-/verdaccio/', webAPI(config, auth, storage)); } else { - app.get('/', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) { + app.get('/', function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) { next(ErrorCode.getNotFound(API_ERROR.WEB_DISABLED)); }); } // Catch 404 - app.get('/*', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) { + app.get('/*', function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) { next(ErrorCode.getNotFound(API_ERROR.FILE_NOT_FOUND)); }); - app.use(function(err: HttpError, req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) { + app.use(function ( + err: HttpError, + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer + ) { if (_.isError(err)) { if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) { return next(); @@ -99,15 +118,20 @@ const defineAPI = function(config: IConfig, storage: IStorageHandler): any { return app; }; -export default (async function(configHash: any): Promise { +export default (async function (configHash: any): Promise { setup(configHash.logs); const config: IConfig = new AppConfig(_.cloneDeep(configHash)); // register middleware plugins const plugin_params = { config: config, - logger: logger, + logger: logger }; - const filters = loadPlugin(config, config.filters || {}, plugin_params, (plugin: IPluginStorageFilter) => plugin.filter_metadata); + const filters = loadPlugin( + config, + config.filters || {}, + plugin_params, + (plugin: IPluginStorageFilter) => plugin.filter_metadata + ); const storage: IStorageHandler = new Storage(config); // waits until init calls have been initialized await storage.init(config, filters); diff --git a/src/api/middleware.ts b/src/api/middleware.ts index cbdc98293..6de118314 100644 --- a/src/api/middleware.ts +++ b/src/api/middleware.ts @@ -1,15 +1,33 @@ import _ from 'lodash'; -import { validateName as utilValidateName, validatePackage as utilValidatePackage, getVersionFromTarball, isObject, ErrorCode } from '../lib/utils'; -import { API_ERROR, HEADER_TYPE, HEADERS, HTTP_STATUS, TOKEN_BASIC, TOKEN_BEARER } from '../lib/constants'; +import { Config, Package, RemoteUser } from '@verdaccio/types'; +import { VerdaccioError } from '@verdaccio/commons-api'; +import { + validateName as utilValidateName, + validatePackage as utilValidatePackage, + getVersionFromTarball, + isObject, + ErrorCode +} from '../lib/utils'; +import { + API_ERROR, + HEADER_TYPE, + HEADERS, + HTTP_STATUS, + TOKEN_BASIC, + TOKEN_BEARER +} from '../lib/constants'; import { stringToMD5 } from '../lib/crypto-utils'; import { $ResponseExtend, $RequestExtend, $NextFunctionVer, IAuth } from '../../types'; -import { Config, Package, RemoteUser } from '@verdaccio/types'; import { logger } from '../lib/logger'; -import { VerdaccioError } from '@verdaccio/commons-api'; export function match(regexp: RegExp): any { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer, value: string): void { + return function ( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer, + value: string + ): void { if (regexp.exec(value)) { next(); } else { @@ -18,7 +36,11 @@ export function match(regexp: RegExp): any { }; } -export function setSecurityWebHeaders(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { +export function setSecurityWebHeaders( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer +): void { // disable loading in frames (clickjacking, etc.) res.header(HEADERS.FRAMES_OPTIONS, 'deny'); // avoid stablish connections outside of domain @@ -32,7 +54,13 @@ export function setSecurityWebHeaders(req: $RequestExtend, res: $ResponseExtend, // flow: express does not match properly // flow info https://github.com/flowtype/flow-typed/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+express -export function validateName(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer, value: string, name: string): void { +export function validateName( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer, + value: string, + name: string +): void { if (value === '-') { // special case in couchdb usually next('route'); @@ -45,7 +73,13 @@ export function validateName(req: $RequestExtend, res: $ResponseExtend, next: $N // flow: express does not match properly // flow info https://github.com/flowtype/flow-typed/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+express -export function validatePackage(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer, value: string, name: string): void { +export function validatePackage( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer, + value: string, + name: string +): void { if (value === '-') { // special case in couchdb usually next('route'); @@ -57,16 +91,28 @@ export function validatePackage(req: $RequestExtend, res: $ResponseExtend, next: } export function media(expect: string | null): any { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { if (req.headers[HEADER_TYPE.CONTENT_TYPE] !== expect) { - next(ErrorCode.getCode(HTTP_STATUS.UNSUPPORTED_MEDIA, 'wrong content-type, expect: ' + expect + ', got: ' + req.headers[HEADER_TYPE.CONTENT_TYPE])); + next( + ErrorCode.getCode( + HTTP_STATUS.UNSUPPORTED_MEDIA, + 'wrong content-type, expect: ' + + expect + + ', got: ' + + req.headers[HEADER_TYPE.CONTENT_TYPE] + ) + ); } else { next(); } }; } -export function encodeScopePackage(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { +export function encodeScopePackage( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer +): void { if (req.url.indexOf('@') !== -1) { // e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3 req.url = req.url.replace(/^(\/@[^\/%]+)\/(?!$)/, '$1%2F'); @@ -74,7 +120,11 @@ export function encodeScopePackage(req: $RequestExtend, res: $ResponseExtend, ne next(); } -export function expectJson(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { +export function expectJson( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer +): void { if (!isObject(req.body)) { return next(ErrorCode.getBadRequest("can't parse incoming json")); } @@ -82,7 +132,7 @@ export function expectJson(req: $RequestExtend, res: $ResponseExtend, next: $Nex } export function antiLoop(config: Config): Function { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { if (req.headers.via != null) { const arr = req.headers.via.split(','); @@ -98,26 +148,37 @@ export function antiLoop(config: Config): Function { } export function allow(auth: IAuth): Function { - return function(action: string): Function { - return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + return function (action: string): Function { + return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { req.pause(); - const packageName = req.params.scope ? `@${req.params.scope}/${req.params.package}` : req.params.package; - const packageVersion = req.params.filename ? getVersionFromTarball(req.params.filename) : undefined; + const packageName = req.params.scope + ? `@${req.params.scope}/${req.params.package}` + : req.params.package; + const packageVersion = req.params.filename + ? getVersionFromTarball(req.params.filename) + : undefined; const remote: RemoteUser = req.remote_user; - logger.trace({ action, user: remote.name }, `[middleware/allow][@{action}] allow for @{user}`); + logger.trace( + { action, user: remote.name }, + `[middleware/allow][@{action}] allow for @{user}` + ); - auth['allow_' + action]({ packageName, packageVersion }, remote, function(error, allowed): void { - req.resume(); - if (error) { - next(error); - } else if (allowed) { - next(); - } else { - // last plugin (that's our built-in one) returns either - // cb(err) or cb(null, true), so this should never happen - throw ErrorCode.getInternalError(API_ERROR.PLUGIN_ERROR); + auth['allow_' + action]( + { packageName, packageVersion }, + remote, + function (error, allowed): void { + req.resume(); + if (error) { + next(error); + } else if (allowed) { + next(); + } else { + // last plugin (that's our built-in one) returns either + // cb(err) or cb(null, true), so this should never happen + throw ErrorCode.getInternalError(API_ERROR.PLUGIN_ERROR); + } } - }); + ); }; }; } @@ -128,7 +189,12 @@ export interface MiddlewareError { export type FinalBody = Package | MiddlewareError | string; -export function final(body: FinalBody, req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { +export function final( + body: FinalBody, + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer +): void { if (res.statusCode === HTTP_STATUS.UNAUTHORIZED && !res.getHeader(HEADERS.WWW_AUTH)) { // they say it's required for 401, so... res.header(HEADERS.WWW_AUTH, `${TOKEN_BASIC}, ${TOKEN_BEARER}`); @@ -148,7 +214,10 @@ export function final(body: FinalBody, req: $RequestExtend, res: $ResponseExtend } // don't send etags with errors - if (!res.statusCode || (res.statusCode >= HTTP_STATUS.OK && res.statusCode < HTTP_STATUS.MULTIPLE_CHOICES)) { + if ( + !res.statusCode || + (res.statusCode >= HTTP_STATUS.OK && res.statusCode < HTTP_STATUS.MULTIPLE_CHOICES) + ) { res.header(HEADERS.ETAG, '"' + stringToMD5(body as string) + '"'); } } else { @@ -170,7 +239,8 @@ export function final(body: FinalBody, req: $RequestExtend, res: $ResponseExtend res.send(body); } -export const LOG_STATUS_MESSAGE = "@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'"; +export const LOG_STATUS_MESSAGE = + "@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}'"; export const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`; export const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`; @@ -192,7 +262,7 @@ export function log(config: Config) { req.url = req.originalUrl; // avoid log noise data from static content if (req.originalUrl.match(/static/) === null) { - req.log.info({req: req, ip: req.ip}, "@{ip} requested '@{req.method} @{req.url}'"); + req.log.info({ req: req, ip: req.ip }, "@{ip} requested '@{req.method} @{req.url}'"); } req.originalUrl = req.url; @@ -206,7 +276,7 @@ export function log(config: Config) { let bytesin = 0; if (config?.experiments?.bytesin_off !== true) { - req.on('data', function(chunk): void { + req.on('data', function (chunk): void { bytesin += chunk.length; }); } @@ -215,7 +285,7 @@ export function log(config: Config) { const _write = res.write; // FIXME: res.write should return boolean // @ts-ignore - res.write = function(buf): boolean { + res.write = function (buf): boolean { bytesout += buf.length; /* eslint prefer-rest-params: "off" */ // @ts-ignore @@ -223,7 +293,7 @@ export function log(config: Config) { }; let logHasBeenCalled = false; - const log = function(): void { + const log = function (): void { if (logHasBeenCalled) { return; } @@ -243,33 +313,33 @@ export function log(config: Config) { // avoid log noise data from static content if (req.url.match(/static/) === null) { req.log.warn( - { - request: { - method: req.method, - url: req.url, - }, - level: 35, // http - user: (req.remote_user && req.remote_user.name) || null, - remoteIP, - status: res.statusCode, - error: res._verdaccio_error, - bytes: { - in: bytesin, - out: bytesout, - }, + { + request: { + method: req.method, + url: req.url }, - message + level: 35, // http + user: (req.remote_user && req.remote_user.name) || null, + remoteIP, + status: res.statusCode, + error: res._verdaccio_error, + bytes: { + in: bytesin, + out: bytesout + } + }, + message ); req.originalUrl = req.url; } - } + }; - req.on('close', function(): void { + req.on('close', function (): void { log(); }); const _end = res.end; - res.end = function(buf): void { + res.end = function (buf): void { if (buf) { bytesout += buf.length; } @@ -279,14 +349,18 @@ export function log(config: Config) { log(); }; next(); - } + }; } // Middleware -export function errorReportingMiddleware(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { +export function errorReportingMiddleware( + req: $RequestExtend, + res: $ResponseExtend, + next: $NextFunctionVer +): void { res.report_error = res.report_error || - function(err: VerdaccioError): void { + function (err: VerdaccioError): void { if (err.status && err.status >= HTTP_STATUS.BAD_REQUEST && err.status < 600) { if (!res.headersSent) { res.status(err.status); diff --git a/src/api/web/api.ts b/src/api/web/api.ts index b480fa3c1..3db484ef6 100644 --- a/src/api/web/api.ts +++ b/src/api/web/api.ts @@ -1,20 +1,19 @@ import { Router } from 'express'; import bodyParser from 'body-parser'; +import { Config } from '@verdaccio/types'; +import Search from '../../lib/search'; +import { match, validateName, validatePackage, setSecurityWebHeaders } from '../middleware'; +import { IAuth, IStorageHandler } from '../../../types'; import addUserAuthApi from './endpoint/user'; import addPackageWebApi from './endpoint/package'; import addSearchWebApi from './endpoint/search'; -import Search from '../../lib/search'; -import { match, validateName, validatePackage, setSecurityWebHeaders } from '../middleware'; -import { Config } from '@verdaccio/types'; -import { IAuth, IStorageHandler } from '../../../types'; - const route = Router(); /* eslint new-cap: 0 */ /* This file include all verdaccio only API(Web UI), for npm API please see ../endpoint/ */ -export default function(config: Config, auth: IAuth, storage: IStorageHandler): Router { +export default function (config: Config, auth: IAuth, storage: IStorageHandler): Router { Search.configureStorage(storage); // validate all of these params as a package name diff --git a/src/api/web/endpoint/package.ts b/src/api/web/endpoint/package.ts index eeb593f32..9fd08aafc 100644 --- a/src/api/web/endpoint/package.ts +++ b/src/api/web/endpoint/package.ts @@ -1,4 +1,6 @@ import _ from 'lodash'; +import { Router } from 'express'; +import { Config, Package } from '@verdaccio/types'; import { addScope, addGravatarSupport, @@ -14,115 +16,148 @@ import { allow } from '../../middleware'; import { DIST_TAGS, HEADER_TYPE, HEADERS, HTTP_STATUS } from '../../../lib/constants'; import { generateGravatarUrl } from '../../../utils/user'; import { logger } from '../../../lib/logger'; -import { Router } from 'express'; -import { IAuth, $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler, $SidebarPackage } from '../../../../types'; -import { Config, Package } from '@verdaccio/types'; +import { + IAuth, + $ResponseExtend, + $RequestExtend, + $NextFunctionVer, + IStorageHandler, + $SidebarPackage +} from '../../../../types'; const getOrder = (order = 'asc') => { return order === 'asc'; }; -export type PackcageExt = Package & { author: any, dist?: {tarball: string} }; +export type PackcageExt = Package & { author: any; dist?: { tarball: string } }; -function addPackageWebApi(route: Router, storage: IStorageHandler, auth: IAuth, config: Config): void { +function addPackageWebApi( + route: Router, + storage: IStorageHandler, + auth: IAuth, + config: Config +): void { const can = allow(auth); const checkAllow = (name, remoteUser): Promise => - new Promise( - (resolve, reject): void => { - try { - auth.allow_access( - { packageName: name }, - remoteUser, - (err, allowed): void => { - if (err) { - resolve(false); - } - resolve(allowed); - } - ); - } catch (err) { - reject(err); - } + new Promise((resolve, reject): void => { + try { + auth.allow_access({ packageName: name }, remoteUser, (err, allowed): void => { + if (err) { + resolve(false); + } + resolve(allowed); + }); + } catch (err) { + reject(err); } - ); + }); // Get list of all visible package - route.get('/packages', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - storage.getLocalDatabase(async function(err, packages): Promise { - if (err) { - throw err; - } - - async function processPackages(packages: PackcageExt[] = []): Promise { - const permissions: PackcageExt[] = []; - const packgesCopy = packages.slice(); - for (const pkg of packgesCopy) { - const pkgCopy = { ...pkg }; - pkgCopy.author = formatAuthor(pkg.author); - try { - if (await checkAllow(pkg.name, req.remote_user)) { - if (config.web) { - pkgCopy.author.avatar = generateGravatarUrl(pkgCopy.author.email, config.web.gravatar); - } - if (!_.isNil(pkgCopy.dist) && !_.isNull(pkgCopy.dist.tarball)) { - pkgCopy.dist.tarball = getLocalRegistryTarballUri(pkgCopy.dist.tarball, pkg.name, req, config.url_prefix); - } - permissions.push(pkgCopy); - } - } catch (err) { - logger.logger.error({ name: pkg.name, error: err }, 'permission process for @{name} has failed: @{error}'); - throw err; - } + route.get( + '/packages', + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + storage.getLocalDatabase(async function (err, packages): Promise { + if (err) { + throw err; } - return permissions; - } + async function processPackages(packages: PackcageExt[] = []): Promise { + const permissions: PackcageExt[] = []; + const packgesCopy = packages.slice(); + for (const pkg of packgesCopy) { + const pkgCopy = { ...pkg }; + pkgCopy.author = formatAuthor(pkg.author); + try { + if (await checkAllow(pkg.name, req.remote_user)) { + if (config.web) { + pkgCopy.author.avatar = generateGravatarUrl( + pkgCopy.author.email, + config.web.gravatar + ); + } + if (!_.isNil(pkgCopy.dist) && !_.isNull(pkgCopy.dist.tarball)) { + pkgCopy.dist.tarball = getLocalRegistryTarballUri( + pkgCopy.dist.tarball, + pkg.name, + req, + config.url_prefix + ); + } + permissions.push(pkgCopy); + } + } catch (err) { + logger.logger.error( + { name: pkg.name, error: err }, + 'permission process for @{name} has failed: @{error}' + ); + throw err; + } + } - const { web } = config; - // @ts-ignore - const order: boolean = config.web ? getOrder(web.sort_packages) : true; + return permissions; + } - next(sortByName(await processPackages(packages), order)); - }); - }); + const { web } = config; + // @ts-ignore + const order: boolean = config.web ? getOrder(web.sort_packages) : true; + + next(sortByName(await processPackages(packages), order)); + }); + } + ); // Get package readme - route.get('/package/readme/(@:scope/)?:package/:version?', can('access'), function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - const packageName = req.params.scope ? addScope(req.params.scope, req.params.package) : req.params.package; + route.get( + '/package/readme/(@:scope/)?:package/:version?', + can('access'), + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + const packageName = req.params.scope + ? addScope(req.params.scope, req.params.package) + : req.params.package; - storage.getPackage({ - name: packageName, - uplinksLook: true, - req, - callback: function(err, info): void { - if (err) { - return next(err); + storage.getPackage({ + name: packageName, + uplinksLook: true, + req, + callback: function (err, info): void { + if (err) { + return next(err); + } + + res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN); + next(parseReadme(info.name, info.readme)); } + }); + } + ); - res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN); - next(parseReadme(info.name, info.readme)); - }, - }); - }); + route.get( + '/sidebar/(@:scope/)?:package', + can('access'), + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + const packageName: string = req.params.scope + ? addScope(req.params.scope, req.params.package) + : req.params.package; - route.get('/sidebar/(@:scope/)?:package', can('access'), function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - const packageName: string = req.params.scope ? addScope(req.params.scope, req.params.package) : req.params.package; - - storage.getPackage({ - name: packageName, - uplinksLook: true, - keepUpLinkData: true, - req, - callback: function(err: Error, info: $SidebarPackage): void { - if (_.isNil(err)) { - const {v} = req.query; - let sideBarInfo: any = _.clone(info); - sideBarInfo.versions = convertDistRemoteToLocalTarballUrls(info, req, config.url_prefix).versions; - if (isVersionValid(info, v)) { - // @ts-ignore - sideBarInfo.latest = sideBarInfo.versions[v]; - sideBarInfo.latest.author = formatAuthor(sideBarInfo.latest.author); + storage.getPackage({ + name: packageName, + uplinksLook: true, + keepUpLinkData: true, + req, + callback: function (err: Error, info: $SidebarPackage): void { + if (_.isNil(err)) { + const { v } = req.query; + let sideBarInfo: any = _.clone(info); + sideBarInfo.versions = convertDistRemoteToLocalTarballUrls( + info, + req, + config.url_prefix + ).versions; + if (isVersionValid(info, v)) { + // @ts-ignore + sideBarInfo.latest = sideBarInfo.versions[v]; + sideBarInfo.latest.author = formatAuthor(sideBarInfo.latest.author); } else { sideBarInfo.latest = sideBarInfo.versions[info[DIST_TAGS].latest]; if (sideBarInfo?.latest) { @@ -145,8 +180,9 @@ function addPackageWebApi(route: Router, storage: IStorageHandler, auth: IAuth, res.end(); } } - }); - }); + }); + } + ); } export default addPackageWebApi; diff --git a/src/api/web/endpoint/search.ts b/src/api/web/endpoint/search.ts index abb6d500a..bfadc8330 100644 --- a/src/api/web/endpoint/search.ts +++ b/src/api/web/endpoint/search.ts @@ -3,49 +3,62 @@ * @flow */ +import { Router } from 'express'; +import { Package } from '@verdaccio/types'; import Search from '../../../lib/search'; import { DIST_TAGS } from '../../../lib/constants'; -import { Router } from 'express'; -import { IAuth, $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler } from '../../../../types'; -import { Package } from '@verdaccio/types'; +import { + IAuth, + $ResponseExtend, + $RequestExtend, + $NextFunctionVer, + IStorageHandler +} from '../../../../types'; function addSearchWebApi(route: Router, storage: IStorageHandler, auth: IAuth): void { // Search package - route.get('/search/:anything', function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { - const results: any = Search.query(req.params.anything); - // FUTURE: figure out here the correct type - const packages: any[] = []; + route.get( + '/search/:anything', + function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void { + const results: any = Search.query(req.params.anything); + // FUTURE: figure out here the correct type + const packages: any[] = []; - const getPackageInfo = function(i): void { - storage.getPackage({ - name: results[i].ref, - uplinksLook: false, - callback: (err, entry: Package): void => { - if (!err && entry) { - auth.allow_access({ packageName: entry.name }, req.remote_user, function(err, allowed): void { - if (err || !allowed) { - return; - } + const getPackageInfo = function (i): void { + storage.getPackage({ + name: results[i].ref, + uplinksLook: false, + callback: (err, entry: Package): void => { + if (!err && entry) { + auth.allow_access( + { packageName: entry.name }, + req.remote_user, + function (err, allowed): void { + if (err || !allowed) { + return; + } - packages.push(entry.versions[entry[DIST_TAGS].latest]); - }); + packages.push(entry.versions[entry[DIST_TAGS].latest]); + } + ); + } + + if (i >= results.length - 1) { + next(packages); + } else { + getPackageInfo(i + 1); + } } + }); + }; - if (i >= results.length - 1) { - next(packages); - } else { - getPackageInfo(i + 1); - } - }, - }); - }; - - if (results.length) { - getPackageInfo(0); - } else { - next([]); + if (results.length) { + getPackageInfo(0); + } else { + next([]); + } } - }); + ); } export default addSearchWebApi; diff --git a/src/api/web/endpoint/user.ts b/src/api/web/endpoint/user.ts index 15015abe9..11754bf90 100644 --- a/src/api/web/endpoint/user.ts +++ b/src/api/web/endpoint/user.ts @@ -4,16 +4,16 @@ */ import _ from 'lodash'; -import { API_ERROR, APP_ERROR, HTTP_STATUS } from '../../../lib/constants'; import { Router, Response, Request } from 'express'; import { Config, RemoteUser, JWTSignOptions } from '@verdaccio/types'; +import { API_ERROR, APP_ERROR, HTTP_STATUS } from '../../../lib/constants'; import { IAuth, $NextFunctionVer } from '../../../../types'; import { ErrorCode } from '../../../lib/utils'; import { getSecurity, validatePassword } from '../../../lib/auth-utils'; function addUserAuthApi(route: Router, auth: IAuth, config: Config): void { - route.post('/login', function(req: Request, res: Response, next: $NextFunctionVer): void { + route.post('/login', function (req: Request, res: Response, next: $NextFunctionVer): void { const { username, password } = req.body; auth.authenticate( @@ -29,39 +29,42 @@ function addUserAuthApi(route: Router, auth: IAuth, config: Config): void { next({ token: await auth.jwtEncrypt(user, jWTSignOptions), - username: req.remote_user.name, + username: req.remote_user.name }); } } ); }); - route.put('/reset_password', function(req: Request, res: Response, next: $NextFunctionVer): void { - if (_.isNil(req.remote_user.name)) { - res.status(HTTP_STATUS.UNAUTHORIZED); - return next({ - // FUTURE: update to a more meaningful message - message: API_ERROR.MUST_BE_LOGGED, - }); - } + route.put( + '/reset_password', + function (req: Request, res: Response, next: $NextFunctionVer): void { + if (_.isNil(req.remote_user.name)) { + res.status(HTTP_STATUS.UNAUTHORIZED); + return next({ + // FUTURE: update to a more meaningful message + message: API_ERROR.MUST_BE_LOGGED + }); + } - const { password } = req.body; - const { name } = req.remote_user; + const { password } = req.body; + const { name } = req.remote_user; - if (validatePassword(password.new) === false) { - auth.changePassword(name as string, password.old, password.new, (err, isUpdated): void => { - if (_.isNil(err) && isUpdated) { - next({ - ok: true, - }); - } else { - return next(ErrorCode.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR)); - } - }); - } else { - return next(ErrorCode.getCode(HTTP_STATUS.BAD_REQUEST, APP_ERROR.PASSWORD_VALIDATION)); + if (validatePassword(password.new) === false) { + auth.changePassword(name as string, password.old, password.new, (err, isUpdated): void => { + if (_.isNil(err) && isUpdated) { + next({ + ok: true + }); + } else { + return next(ErrorCode.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR)); + } + }); + } else { + return next(ErrorCode.getCode(HTTP_STATUS.BAD_REQUEST, APP_ERROR.PASSWORD_VALIDATION)); + } } - }); + ); } export default addUserAuthApi; diff --git a/src/api/web/index.ts b/src/api/web/index.ts index bcd89e7ca..d55cf5879 100644 --- a/src/api/web/index.ts +++ b/src/api/web/index.ts @@ -2,10 +2,10 @@ * @prettier */ -import _ from 'lodash'; import fs from 'fs'; import path from 'path'; +import _ from 'lodash'; import express from 'express'; import { combineBaseUrl, getWebProtocol, isHTTPProtocol } from '../../lib/utils'; @@ -25,7 +25,7 @@ export function loadTheme(config) { config, config.theme, {}, - function(plugin) { + function (plugin) { return _.isString(plugin); }, 'verdaccio-theme' @@ -43,7 +43,7 @@ export function validatePrimaryColor(primaryColor) { return primaryColor; } -const sendFileCallback = next => err => { +const sendFileCallback = (next) => (err) => { if (!err) { return; } @@ -54,7 +54,7 @@ const sendFileCallback = next => err => { } }; -export default function(config, auth, storage) { +export default function (config, auth, storage) { Search.configureStorage(storage); /* eslint new-cap:off */ const router = express.Router(); @@ -73,13 +73,13 @@ export default function(config, auth, storage) { // Note: `path.join` will break on Windows, because it transforms `/` to `\` // Use POSIX version `path.posix.join` instead. logoURI = path.posix.join('/-/static/', path.basename(logoURI)); - router.get(logoURI, function(req, res, next) { + router.get(logoURI, function (req, res, next) { res.sendFile(path.resolve(config.web.logo), sendFileCallback(next)); }); } // Static - router.get('/-/static/*', function(req, res, next) { + router.get('/-/static/*', function (req, res, next) { const filename = req.params[0]; const file = `${themePath}/${filename}`; res.sendFile(file, sendFileCallback(next)); @@ -106,7 +106,7 @@ export default function(config, auth, storage) { primaryColor, title, scope, - language, + language }; const webPage = template @@ -124,11 +124,11 @@ export default function(config, auth, storage) { res.send(webPage); } - router.get('/-/web/:section/*', function(req, res) { + router.get('/-/web/:section/*', function (req, res) { renderHTML(req, res); }); - router.get('/', function(req, res) { + router.get('/', function (req, res) { renderHTML(req, res); }); diff --git a/src/config/env.ts b/src/config/env.ts index b488602b7..4f1620400 100644 --- a/src/config/env.ts +++ b/src/config/env.ts @@ -9,5 +9,5 @@ const APP_ROOT = path.resolve(__dirname, '../../'); module.exports = { APP_ROOT, SRC_ROOT: path.resolve(APP_ROOT, 'src/'), - DIST_PATH: path.resolve(APP_ROOT, 'static/'), + DIST_PATH: path.resolve(APP_ROOT, 'static/') }; diff --git a/src/index.ts b/src/index.ts index 858bce321..e41843bd6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ // @flow -import {startVerdaccio} from './lib/bootstrap'; +import { startVerdaccio } from './lib/bootstrap'; export default startVerdaccio; diff --git a/src/lib/auth-utils.ts b/src/lib/auth-utils.ts index 92815a536..abfc52fbb 100644 --- a/src/lib/auth-utils.ts +++ b/src/lib/auth-utils.ts @@ -1,14 +1,39 @@ import _ from 'lodash'; +import { + RemoteUser, + Package, + Callback, + Config, + Security, + APITokenOptions, + JWTOptions, + IPluginAuth +} from '@verdaccio/types'; +import { + CookieSessionToken, + IAuthWebUI, + AuthMiddlewarePayload, + AuthTokenHeader, + BasicPayload +} from '../../types'; +import { logger } from '../lib/logger'; import { convertPayloadToBase64, ErrorCode } from './utils'; -import { API_ERROR, HTTP_STATUS, ROLES, TIME_EXPIRATION_7D, TOKEN_BASIC, TOKEN_BEARER, DEFAULT_MIN_LIMIT_PASSWORD } from './constants'; +import { + API_ERROR, + HTTP_STATUS, + ROLES, + TIME_EXPIRATION_7D, + TOKEN_BASIC, + TOKEN_BEARER, + DEFAULT_MIN_LIMIT_PASSWORD +} from './constants'; -import { RemoteUser, Package, Callback, Config, Security, APITokenOptions, JWTOptions, IPluginAuth } from '@verdaccio/types'; -import { CookieSessionToken, IAuthWebUI, AuthMiddlewarePayload, AuthTokenHeader, BasicPayload } from '../../types'; import { aesDecrypt, verifyPayload } from './crypto-utils'; -import { logger } from '../lib/logger'; - -export function validatePassword(password: string, minLength: number = DEFAULT_MIN_LIMIT_PASSWORD): boolean { +export function validatePassword( + password: string, + minLength: number = DEFAULT_MIN_LIMIT_PASSWORD +): boolean { return typeof password === 'string' && password.length >= minLength; } @@ -18,12 +43,18 @@ export function validatePassword(password: string, minLength: number = DEFAULT_M */ export function createRemoteUser(name: string, pluginGroups: string[]): RemoteUser { const isGroupValid: boolean = Array.isArray(pluginGroups); - const groups = (isGroupValid ? pluginGroups : []).concat([ROLES.$ALL, ROLES.$AUTH, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_AUTH, ROLES.ALL]); + const groups = (isGroupValid ? pluginGroups : []).concat([ + ROLES.$ALL, + ROLES.$AUTH, + ROLES.DEPRECATED_ALL, + ROLES.DEPRECATED_AUTH, + ROLES.ALL + ]); return { name, groups, - real_groups: pluginGroups, + real_groups: pluginGroups }; } @@ -36,27 +67,34 @@ export function createAnonymousRemoteUser(): RemoteUser { name: undefined, // groups without '$' are going to be deprecated eventually groups: [ROLES.$ALL, ROLES.$ANONYMOUS, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_ANONYMOUS], - real_groups: [], + real_groups: [] }; } export function allow_action(action: string): Function { - return function(user: RemoteUser, pkg: Package, callback: Callback): void { - logger.trace({remote: user.name}, `[auth/allow_action]: user: @{user.name}`); + return function (user: RemoteUser, pkg: Package, callback: Callback): void { + logger.trace({ remote: user.name }, `[auth/allow_action]: user: @{user.name}`); const { name, groups } = user; const groupAccess = pkg[action]; - const hasPermission = groupAccess.some(group => name === group || groups.includes(group)); - logger.trace({pkgName: pkg.name, hasPermission, remote: user.name, groupAccess}, `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{user}`); + const hasPermission = groupAccess.some((group) => name === group || groups.includes(group)); + logger.trace( + { pkgName: pkg.name, hasPermission, remote: user.name, groupAccess }, + `[auth/allow_action]: hasPermission? @{hasPermission} for user: @{user}` + ); if (hasPermission) { - logger.trace({remote: user.name}, `auth/allow_action: access granted to: @{user}`); + logger.trace({ remote: user.name }, `auth/allow_action: access granted to: @{user}`); return callback(null, true); } if (name) { - callback(ErrorCode.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`)); + callback( + ErrorCode.getForbidden(`user ${name} is not allowed to ${action} package ${pkg.name}`) + ); } else { - callback(ErrorCode.getUnauthorized(`authorization required to ${action} package ${pkg.name}`)); + callback( + ErrorCode.getUnauthorized(`authorization required to ${action} package ${pkg.name}`) + ); } }; } @@ -65,18 +103,24 @@ export function allow_action(action: string): Function { * */ export function handleSpecialUnpublish(): any { - return function(user: RemoteUser, pkg: Package, callback: Callback): void { + return function (user: RemoteUser, pkg: Package, callback: Callback): void { const action = 'unpublish'; // verify whether the unpublish prop has been defined const isUnpublishMissing: boolean = _.isNil(pkg[action]); const hasGroups: boolean = isUnpublishMissing ? false : pkg[action].length > 0; - logger.trace({user: user.name, name: pkg.name, hasGroups}, `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}`); + logger.trace( + { user: user.name, name: pkg.name, hasGroups }, + `fallback unpublish for @{name} has groups: @{hasGroups} for @{user}` + ); if (isUnpublishMissing || hasGroups === false) { return callback(null, undefined); } - logger.trace({user: user.name, name: pkg.name, action, hasGroups}, `allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}`); + logger.trace( + { user: user.name, name: pkg.name, action, hasGroups }, + `allow_action for @{action} for @{name} has groups: @{hasGroups} for @{user}` + ); return allow_action(action)(user, pkg, callback); }; } @@ -96,7 +140,7 @@ export function getDefaultPlugins(): IPluginAuth { allow_access: allow_action('access'), // @ts-ignore allow_publish: allow_action('publish'), - allow_unpublish: handleSpecialUnpublish(), + allow_unpublish: handleSpecialUnpublish() }; } @@ -105,25 +149,25 @@ export function createSessionToken(): CookieSessionToken { return { // npmjs.org sets 10h expire - expires: new Date(Date.now() + tenHoursTime), + expires: new Date(Date.now() + tenHoursTime) }; } const defaultWebTokenOptions: JWTOptions = { sign: { // The expiration token for the website is 7 days - expiresIn: TIME_EXPIRATION_7D, + expiresIn: TIME_EXPIRATION_7D }, - verify: {}, + verify: {} }; const defaultApiTokenConf: APITokenOptions = { - legacy: true, + legacy: true }; export const defaultSecurity: Security = { web: defaultWebTokenOptions, - api: defaultApiTokenConf, + api: defaultApiTokenConf }; export function getSecurity(config: Config): Security { @@ -148,13 +192,20 @@ export function isAESLegacy(security: Security): boolean { return _.isNil(legacy) === false && _.isNil(jwt) && legacy === true; } -export async function getApiToken(auth: IAuthWebUI, config: Config, remoteUser: RemoteUser, aesPassword: string): Promise { +export async function getApiToken( + auth: IAuthWebUI, + config: Config, + remoteUser: RemoteUser, + aesPassword: string +): Promise { const security: Security = getSecurity(config); if (isAESLegacy(security)) { // fallback all goes to AES encryption return await new Promise((resolve): void => { - resolve(auth.aesEncrypt(buildUserBuffer(remoteUser.name as string, aesPassword)).toString('base64')); + resolve( + auth.aesEncrypt(buildUserBuffer(remoteUser.name as string, aesPassword)).toString('base64') + ); }); } // i am wiling to use here _.isNil but flow does not like it yet. @@ -164,9 +215,10 @@ export async function getApiToken(auth: IAuthWebUI, config: Config, remoteUser: return await auth.jwtEncrypt(remoteUser, jwt.sign); } return await new Promise((resolve): void => { - resolve(auth.aesEncrypt(buildUserBuffer(remoteUser.name as string, aesPassword)).toString('base64')); + resolve( + auth.aesEncrypt(buildUserBuffer(remoteUser.name as string, aesPassword)).toString('base64') + ); }); - } export function parseAuthTokenHeader(authorizationHeader: string): AuthTokenHeader { @@ -227,7 +279,11 @@ export function isAuthHeaderValid(authorization: string): boolean { return authorization.split(' ').length === 2; } -export function getMiddlewareCredentials(security: Security, secret: string, authorizationHeader: string): AuthMiddlewarePayload { +export function getMiddlewareCredentials( + security: Security, + secret: string, + authorizationHeader: string +): AuthMiddlewarePayload { if (isAESLegacy(security)) { const credentials = parseAESCredentials(authorizationHeader, secret); if (!credentials) { diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 7df8648ed..a999b110f 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,8 +1,22 @@ import _ from 'lodash'; import { VerdaccioError } from '@verdaccio/commons-api'; -import {API_ERROR, SUPPORT_ERRORS, TOKEN_BASIC, TOKEN_BEARER} from './constants'; +import { + Config, + Logger, + Callback, + IPluginAuth, + RemoteUser, + JWTSignOptions, + Security, + AuthPluginPackage, + AllowAccess, + PackageAccess +} from '@verdaccio/types'; +import { NextFunction } from 'express'; import loadPlugin from '../lib/plugin-loader'; +import { $RequestExtend, $ResponseExtend, IAuth, AESPayload } from '../../types'; +import { API_ERROR, SUPPORT_ERRORS, TOKEN_BASIC, TOKEN_BEARER } from './constants'; import { aesEncrypt, signPayload } from './crypto-utils'; import { getDefaultPlugins, @@ -14,15 +28,11 @@ import { isAESLegacy, parseAuthTokenHeader, parseBasicPayload, - createRemoteUser, + createRemoteUser } from './auth-utils'; import { convertPayloadToBase64, ErrorCode } from './utils'; import { getMatchedPackagesSpec } from './config-utils'; -import { Config, Logger, Callback, IPluginAuth, RemoteUser, JWTSignOptions, Security, AuthPluginPackage, AllowAccess, PackageAccess } from '@verdaccio/types'; -import { NextFunction } from 'express'; -import { $RequestExtend, $ResponseExtend, IAuth, AESPayload } from '../../types'; - /* eslint-disable @typescript-eslint/no-var-requires */ const LoggerApi = require('./logger'); @@ -43,7 +53,7 @@ class Auth implements IAuth { private _loadPlugin(config: Config): IPluginAuth[] { const pluginOptions = { config, - logger: this.logger, + logger: this.logger }; return loadPlugin>( @@ -63,39 +73,39 @@ class Auth implements IAuth { this.plugins.push(getDefaultPlugins()); } - public changePassword(username: string, password: string, newPassword: string, cb: Callback): void { - const validPlugins = _.filter(this.plugins, plugin => _.isFunction(plugin.changePassword)); + public changePassword( + username: string, + password: string, + newPassword: string, + cb: Callback + ): void { + const validPlugins = _.filter(this.plugins, (plugin) => _.isFunction(plugin.changePassword)); - if (_.isEmpty(validPlugins)) { - return cb(ErrorCode.getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE)); - } + if (_.isEmpty(validPlugins)) { + return cb(ErrorCode.getInternalError(SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE)); + } - for (const plugin of validPlugins) { - if (_.isNil(plugin) || _.isFunction(plugin.changePassword) === false) { - this.logger.trace('auth plugin does not implement changePassword, trying next one'); - continue; - } else { - this.logger.trace({username}, 'updating password for @{username}'); - plugin.changePassword!( - username, - password, - newPassword, - (err, profile): void => { - if (err) { - this.logger.error( - {username, err}, - `An error has been produced + for (const plugin of validPlugins) { + if (_.isNil(plugin) || _.isFunction(plugin.changePassword) === false) { + this.logger.trace('auth plugin does not implement changePassword, trying next one'); + continue; + } else { + this.logger.trace({ username }, 'updating password for @{username}'); + plugin.changePassword!(username, password, newPassword, (err, profile): void => { + if (err) { + this.logger.error( + { username, err }, + `An error has been produced updating the password for @{username}. Error: @{err.message}` - ); - return cb(err); - } + ); + return cb(err); + } - this.logger.trace({username}, 'updated password for @{username} was successful'); - return cb(null, profile); - } - ); - } - } + this.logger.trace({ username }, 'updated password for @{username} was successful'); + return cb(null, profile); + }); + } + } } public authenticate(username: string, password: string, cb: Callback): void { @@ -109,9 +119,12 @@ class Auth implements IAuth { } self.logger.trace({ username }, 'authenticating @{username}'); - plugin.authenticate(username, password, function(err, groups): void { + plugin.authenticate(username, password, function (err, groups): void { if (err) { - self.logger.trace({ username, err }, 'authenticating for user @{username} failed. Error: @{err.message}'); + self.logger.trace( + { username, err }, + 'authenticating for user @{username} failed. Error: @{err.message}' + ); return cb(err); } @@ -132,7 +145,10 @@ class Auth implements IAuth { throw new TypeError(API_ERROR.BAD_FORMAT_USER_GROUP); } - self.logger.trace({ username, groups }, 'authentication for user @{username} was successfully. Groups: @{groups}'); + self.logger.trace( + { username, groups }, + 'authentication for user @{username} was successfully. Groups: @{groups}' + ); return cb(err, createRemoteUser(username, groups)); } next(); @@ -150,16 +166,21 @@ class Auth implements IAuth { let method = 'adduser'; if (_.isFunction(plugin[method]) === false) { method = 'add_user'; - self.logger.warn('the plugin method add_user in the auth plugin is deprecated and will be removed in next major release, notify to the plugin author'); + self.logger.warn( + 'the plugin method add_user in the auth plugin is deprecated and will be removed in next major release, notify to the plugin author' + ); } if (_.isFunction(plugin[method]) === false) { next(); } else { // p.add_user() execution - plugin[method](user, password, function(err, ok): void { + plugin[method](user, password, function (err, ok): void { if (err) { - self.logger.trace({ user, err: err.message }, 'the user @{user} could not being added. Error: @{err}'); + self.logger.trace( + { user, err: err.message }, + 'the user @{user} could not being added. Error: @{err}' + ); return cb(err); } if (ok) { @@ -175,10 +196,18 @@ class Auth implements IAuth { /** * Allow user to access a package. */ - public allow_access({ packageName, packageVersion }: AuthPluginPackage, user: RemoteUser, callback: Callback): void { + public allow_access( + { packageName, packageVersion }: AuthPluginPackage, + user: RemoteUser, + callback: Callback + ): void { const plugins = this.plugins.slice(0); const pkgAllowAcces: AllowAccess = { name: packageName, version: packageVersion }; - const pkg = Object.assign({}, pkgAllowAcces, getMatchedPackagesSpec(packageName, this.config.packages)) as AllowAccess & PackageAccess; + const pkg = Object.assign( + {}, + pkgAllowAcces, + getMatchedPackagesSpec(packageName, this.config.packages) + ) as AllowAccess & PackageAccess; const self = this; this.logger.trace({ packageName }, 'allow access for @{packageName}'); @@ -189,9 +218,12 @@ class Auth implements IAuth { return next(); } - plugin.allow_access!(user, pkg, function(err, ok: boolean): void { + plugin.allow_access!(user, pkg, function (err, ok: boolean): void { if (err) { - self.logger.trace({ packageName, err }, 'forbidden access for @{packageName}. Error: @{err.message}'); + self.logger.trace( + { packageName, err }, + 'forbidden access for @{packageName}. Error: @{err.message}' + ); return callback(err); } @@ -205,37 +237,49 @@ class Auth implements IAuth { })(); } - public allow_unpublish({ packageName, packageVersion }: AuthPluginPackage, user: RemoteUser, callback: Callback): void { - const pkg = Object.assign({ name: packageName, version: packageVersion }, getMatchedPackagesSpec(packageName, this.config.packages)); + public allow_unpublish( + { packageName, packageVersion }: AuthPluginPackage, + user: RemoteUser, + callback: Callback + ): void { + const pkg = Object.assign( + { name: packageName, version: packageVersion }, + getMatchedPackagesSpec(packageName, this.config.packages) + ); this.logger.trace({ packageName }, 'allow unpublish for @{packageName}'); for (const plugin of this.plugins) { if (_.isNil(plugin) || _.isFunction(plugin.allow_unpublish) === false) { - this.logger.trace({ packageName }, 'allow unpublish for @{packageName} plugin does not implement allow_unpublish'); + this.logger.trace( + { packageName }, + 'allow unpublish for @{packageName} plugin does not implement allow_unpublish' + ); continue; } else { - plugin.allow_unpublish!( - user, - pkg, - (err, ok: boolean): void => { - 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'); - // @ts-ignore - // eslint-disable-next-line - 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): void => { + 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' + ); + // @ts-ignore + // eslint-disable-next-line + return this.allow_publish(...arguments); + } + + if (ok) { + this.logger.trace({ packageName }, 'allowed unpublish for @{packageName}'); + return callback(null, ok); + } + }); } } } @@ -243,39 +287,48 @@ class Auth implements IAuth { /** * Allow user to publish a package. */ - public allow_publish({ packageName, packageVersion }: AuthPluginPackage, user: RemoteUser, callback: Callback): void { + public allow_publish( + { packageName, packageVersion }: AuthPluginPackage, + user: RemoteUser, + callback: Callback + ): void { const plugins = this.plugins.slice(0); const self = this; - const pkg = Object.assign({ name: packageName, version: packageVersion }, getMatchedPackagesSpec(packageName, this.config.packages)); - this.logger.trace({ packageName, plugins: this.plugins.length }, 'allow publish for @{packageName} init | plugins: @{plugins}'); + const pkg = Object.assign( + { name: packageName, version: packageVersion }, + getMatchedPackagesSpec(packageName, this.config.packages) + ); + this.logger.trace( + { packageName, plugins: this.plugins.length }, + 'allow publish for @{packageName} init | plugins: @{plugins}' + ); (function next(): void { const plugin = plugins.shift(); if (_.isNil(plugin) || _.isFunction(plugin.allow_publish) === false) { - self.logger.trace({ packageName }, 'allow publish for @{packageName} plugin does not implement allow_publish'); + self.logger.trace( + { packageName }, + 'allow publish for @{packageName} plugin does not implement allow_publish' + ); return next(); } // @ts-ignore - plugin.allow_publish( - user, - pkg, - (err: VerdaccioError, ok: boolean): void => { - if (_.isNil(err) === false && _.isError(err)) { - self.logger.trace({ packageName }, 'forbidden publish for @{packageName}'); - return callback(err); - } - - if (ok) { - self.logger.trace({ packageName }, 'allowed publish for @{packageName}'); - return callback(null, ok); - } - - self.logger.trace({ packageName }, 'allow publish skip validation for @{packageName}'); - next(); // cb(null, false) causes next plugin to roll + plugin.allow_publish(user, pkg, (err: VerdaccioError, ok: boolean): void => { + if (_.isNil(err) === false && _.isError(err)) { + self.logger.trace({ packageName }, 'forbidden publish for @{packageName}'); + return callback(err); } - ); + + if (ok) { + self.logger.trace({ packageName }, 'allowed publish for @{packageName}'); + return callback(null, ok); + } + + self.logger.trace({ packageName }, 'allow publish skip validation for @{packageName}'); + next(); // cb(null, false) causes next plugin to roll + }); })(); } @@ -291,7 +344,7 @@ class Auth implements IAuth { return (req: $RequestExtend, res: $ResponseExtend, _next: NextFunction): void => { req.pause(); - const next = function(err: VerdaccioError | void): void { + const next = function (err: VerdaccioError | void): void { req.resume(); // uncomment this to reject users with bad auth headers // return _next.apply(null, arguments) @@ -333,25 +386,27 @@ class Auth implements IAuth { }; } - private _handleJWTAPIMiddleware(req: $RequestExtend, security: Security, secret: string, authorization: string, next: Function): void { + private _handleJWTAPIMiddleware( + req: $RequestExtend, + security: Security, + secret: string, + authorization: string, + next: Function + ): void { const { scheme, token } = parseAuthTokenHeader(authorization); if (scheme.toUpperCase() === TOKEN_BASIC.toUpperCase()) { // this should happen when client tries to login with an existing user const credentials = convertPayloadToBase64(token).toString(); const { user, password } = parseBasicPayload(credentials) as AESPayload; - this.authenticate( - user, - password, - (err, user): void => { - if (!err) { - req.remote_user = user; - next(); - } else { - req.remote_user = createAnonymousRemoteUser(); - next(err); - } + this.authenticate(user, password, (err, user): void => { + if (!err) { + req.remote_user = user; + next(); + } else { + req.remote_user = createAnonymousRemoteUser(); + next(err); } - ); + }); } else { // jwt handler const credentials: any = getMiddlewareCredentials(security, secret, authorization); @@ -366,23 +421,25 @@ class Auth implements IAuth { } } - private _handleAESMiddleware(req: $RequestExtend, security: Security, secret: string, authorization: string, next: Function): void { + private _handleAESMiddleware( + req: $RequestExtend, + security: Security, + secret: string, + authorization: string, + next: Function + ): void { const credentials: any = getMiddlewareCredentials(security, secret, authorization); if (credentials) { const { user, password } = credentials; - this.authenticate( - user, - password, - (err, user): void => { - if (!err) { - req.remote_user = user; - next(); - } else { - req.remote_user = createAnonymousRemoteUser(); - next(err); - } + this.authenticate(user, password, (err, user): void => { + if (!err) { + req.remote_user = user; + next(); + } else { + req.remote_user = createAnonymousRemoteUser(); + next(err); } - ); + }); } else { // we force npm client to ask again with basic authentication return next(ErrorCode.getBadRequest(API_ERROR.BAD_AUTH_HEADER)); @@ -453,7 +510,7 @@ class Auth implements IAuth { const payload: RemoteUser = { real_groups: realGroupsValidated, name, - groups: groupedGroups, + groups: groupedGroups }; const token: string = await signPayload(payload, this.secret, signOptions); diff --git a/src/lib/bootstrap.ts b/src/lib/bootstrap.ts index 91a3ec8ff..fa8b1e0b4 100644 --- a/src/lib/bootstrap.ts +++ b/src/lib/bootstrap.ts @@ -1,25 +1,29 @@ -import { assign, isObject, isFunction } from 'lodash'; -import express from 'express'; import URL from 'url'; import fs from 'fs'; import http from 'http'; import https from 'https'; import constants from 'constants'; -import endPointAPI from '../api/index'; -import { getListListenAddresses, resolveConfigPath } from './cli/utils'; -import { API_ERROR, certPem, csrPem, keyPem } from './constants'; +import express from 'express'; +import { assign, isObject, isFunction } from 'lodash'; import { Callback, ConfigWithHttps, HttpsConfKeyCert, HttpsConfPfx } from '@verdaccio/types'; import { Application } from 'express'; +import endPointAPI from '../api/index'; +import { API_ERROR, certPem, csrPem, keyPem } from './constants'; +import { getListListenAddresses, resolveConfigPath } from './cli/utils'; const logger = require('./logger'); function displayExperimentsInfoBox(experiments) { const experimentList = Object.keys(experiments); if (experimentList.length >= 1) { - logger.logger.warn('⚠️ experiments are enabled, we recommend do not use experiments in production, comment out this section to disable it'); - experimentList.forEach(experiment => { - logger.logger.warn(` - support for ${experiment} ${experiments[experiment] ? 'is enabled' : ' is disabled'}`); + logger.logger.warn( + '⚠️ experiments are enabled, we recommend do not use experiments in production, comment out this section to disable it' + ); + experimentList.forEach((experiment) => { + logger.logger.warn( + ` - support for ${experiment} ${experiments[experiment] ? 'is enabled' : ' is disabled'}` + ); }); } } @@ -32,7 +36,14 @@ function displayExperimentsInfoBox(experiments) { * @param {String} pkgVersion * @param {String} pkgName */ -function startVerdaccio(config: any, cliListen: string, configPath: string, pkgVersion: string, pkgName: string, callback: Callback): void { +function startVerdaccio( + config: any, + cliListen: string, + configPath: string, + pkgVersion: string, + pkgName: string, + callback: Callback +): void { if (isObject(config) === false) { throw new Error(API_ERROR.CONFIG_BAD_FORMAT); } @@ -41,28 +52,30 @@ function startVerdaccio(config: any, cliListen: string, configPath: string, pkgV displayExperimentsInfoBox(config.experiments); } - endPointAPI(config).then( - (app): void => { - const addresses = getListListenAddresses(cliListen, config.listen); + endPointAPI(config).then((app): void => { + const addresses = getListListenAddresses(cliListen, config.listen); - addresses.forEach(function(addr): void { - let webServer; - if (addr.proto === 'https') { - webServer = handleHTTPS(app, configPath, config); - } else { - // http - webServer = http.createServer(app); - } - if (config.server && typeof config.server.keepAliveTimeout !== 'undefined' && config.server.keepAliveTimeout !== 'null') { - // library definition for node is not up to date (doesn't contain recent 8.0 changes) - webServer.keepAliveTimeout = config.server.keepAliveTimeout * 1000; - } - unlinkAddressPath(addr); + addresses.forEach(function (addr): void { + let webServer; + if (addr.proto === 'https') { + webServer = handleHTTPS(app, configPath, config); + } else { + // http + webServer = http.createServer(app); + } + if ( + config.server && + typeof config.server.keepAliveTimeout !== 'undefined' && + config.server.keepAliveTimeout !== 'null' + ) { + // library definition for node is not up to date (doesn't contain recent 8.0 changes) + webServer.keepAliveTimeout = config.server.keepAliveTimeout * 1000; + } + unlinkAddressPath(addr); - callback(webServer, addr, pkgName, pkgVersion); - }); - } - ); + callback(webServer, addr, pkgName, pkgVersion); + }); + }); } function unlinkAddressPath(addr) { @@ -82,7 +95,10 @@ function logHTTPSWarning(storageLocation) { // commands are borrowed from node.js docs 'To quickly create self-signed certificate, use:', ' $ openssl genrsa -out ' + resolveConfigPath(storageLocation, keyPem) + ' 2048', - ' $ openssl req -new -sha256 -key ' + resolveConfigPath(storageLocation, keyPem) + ' -out ' + resolveConfigPath(storageLocation, csrPem), + ' $ openssl req -new -sha256 -key ' + + resolveConfigPath(storageLocation, keyPem) + + ' -out ' + + resolveConfigPath(storageLocation, csrPem), ' $ openssl x509 -req -in ' + resolveConfigPath(storageLocation, csrPem) + ' -signkey ' + @@ -93,16 +109,20 @@ function logHTTPSWarning(storageLocation) { 'And then add to config file (' + storageLocation + '):', ' https:', ` key: ${resolveConfigPath(storageLocation, keyPem)}`, - ` cert: ${resolveConfigPath(storageLocation, certPem)}`, + ` cert: ${resolveConfigPath(storageLocation, certPem)}` ].join('\n') ); process.exit(2); } -function handleHTTPS(app: express.Application, configPath: string, config: ConfigWithHttps): https.Server { +function handleHTTPS( + app: express.Application, + configPath: string, + config: ConfigWithHttps +): https.Server { try { let httpsOptions = { - secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3, // disable insecure SSLv2 and SSLv3 + secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 // disable insecure SSLv2 and SSLv3 }; const keyCertConfig = config.https as HttpsConfKeyCert; @@ -117,7 +137,7 @@ function handleHTTPS(app: express.Application, configPath: string, config: Confi const { pfx, passphrase } = pfxConfig; httpsOptions = assign(httpsOptions, { pfx: fs.readFileSync(pfx), - passphrase: passphrase || '', + passphrase: passphrase || '' }); } else { const { key, cert, ca } = keyCertConfig; @@ -125,8 +145,8 @@ function handleHTTPS(app: express.Application, configPath: string, config: Confi key: fs.readFileSync(key), cert: fs.readFileSync(cert), ...(ca && { - ca: fs.readFileSync(ca), - }), + ca: fs.readFileSync(ca) + }) }); } return https.createServer(httpsOptions, app); @@ -137,21 +157,22 @@ function handleHTTPS(app: express.Application, configPath: string, config: Confi } } -function listenDefaultCallback(webServer: Application, addr: any, pkgName: string, pkgVersion: string): void { +function listenDefaultCallback( + webServer: Application, + addr: any, + pkgName: string, + pkgVersion: string +): void { webServer - .listen( - addr.port || addr.path, - addr.host, - (): void => { - // send a message for tests - if (isFunction(process.send)) { - process.send({ - verdaccio_started: true, - }); - } + .listen(addr.port || addr.path, addr.host, (): void => { + // send a message for tests + if (isFunction(process.send)) { + process.send({ + verdaccio_started: true + }); } - ) - .on('error', function(err): void { + }) + .on('error', function (err): void { logger.logger.fatal({ err: err }, 'cannot create server: @{err.message}'); process.exit(2); }); @@ -161,15 +182,15 @@ function listenDefaultCallback(webServer: Application, addr: any, pkgName: strin addr: addr.path ? URL.format({ protocol: 'unix', - pathname: addr.path, + pathname: addr.path }) : URL.format({ protocol: addr.proto, hostname: addr.host, port: addr.port, - pathname: '/', + pathname: '/' }), - version: pkgName + '/' + pkgVersion, + version: pkgName + '/' + pkgVersion }, 'http address - @{addr} - @{version}' ); diff --git a/src/lib/cli.ts b/src/lib/cli.ts index 3db4158f5..6ccac2927 100644 --- a/src/lib/cli.ts +++ b/src/lib/cli.ts @@ -2,34 +2,40 @@ /* eslint no-sync:0 */ /* eslint no-empty:0 */ -/** - * @prettier - */ import path from 'path'; import semver from 'semver'; import { bgYellow, bgRed } from 'kleur'; -import {startVerdaccio, listenDefaultCallback} from './bootstrap'; +import { startVerdaccio, listenDefaultCallback } from './bootstrap'; import findConfigFile from './config-path'; import { parseConfigFile } from './utils'; require('pkginfo')(module); if (process.getuid && process.getuid() === 0) { - global.console.warn(bgYellow().red('*** WARNING: Verdaccio doesn\'t need superuser privileges. Don\'t run it under root! ***')); + global.console.warn( + bgYellow().red( + "*** WARNING: Verdaccio doesn't need superuser privileges. Don't run it under root! ***" + ) + ); } const MIN_NODE_VERSION = '6.9.0'; if (semver.satisfies(process.version, `>=${MIN_NODE_VERSION}`) === false) { - global.console.error(bgRed(`Verdaccio requires at least Node.js ${MIN_NODE_VERSION} or higher, please upgrade your Node.js distribution`)); + global.console.error( + bgRed( + `Verdaccio requires at least Node.js ${MIN_NODE_VERSION} or higher, please upgrade your Node.js distribution` + ) + ); process.exit(1); } process.title = 'verdaccio'; +// eslint-disable-next-line import/order const logger = require('./logger'); -logger.setup(null, {logStart: false}); // default setup +logger.setup(null, { logStart: false }); // default setup const envinfo = require('envinfo'); const commander = require('commander'); @@ -51,40 +57,50 @@ function init() { try { configPathLocation = findConfigFile(commander.config); verdaccioConfiguration = parseConfigFile(configPathLocation); - process.title = verdaccioConfiguration.web && verdaccioConfiguration.web.title || 'verdaccio'; + process.title = (verdaccioConfiguration.web && verdaccioConfiguration.web.title) || 'verdaccio'; if (!verdaccioConfiguration.self_path) { verdaccioConfiguration.self_path = path.resolve(configPathLocation); } if (!verdaccioConfiguration.https) { - verdaccioConfiguration.https = {enable: false}; + verdaccioConfiguration.https = { enable: false }; } - logger.logger.warn({file: configPathLocation}, 'config file - @{file}'); + logger.logger.warn({ file: configPathLocation }, 'config file - @{file}'); - startVerdaccio(verdaccioConfiguration, cliListener, configPathLocation, pkgVersion, pkgName, listenDefaultCallback); + startVerdaccio( + verdaccioConfiguration, + cliListener, + configPathLocation, + pkgVersion, + pkgName, + listenDefaultCallback + ); } catch (err) { - logger.logger.fatal({file: configPathLocation, err: err}, 'cannot open config file @{file}: @{!err.message}'); + logger.logger.fatal( + { file: configPathLocation, err: err }, + 'cannot open config file @{file}: @{!err.message}' + ); process.exit(1); } } if (commander.info) { // eslint-disable-next-line no-console - console.log('\nEnvironment Info:'); + console.log('\nEnvironment Info:'); (async () => { const data = await envinfo.run({ - System: ['OS', 'CPU'], - Binaries: ['Node', 'Yarn', 'npm'], - Virtualization: ['Docker'], - Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'], - npmGlobalPackages: ['verdaccio'], - }); + System: ['OS', 'CPU'], + Binaries: ['Node', 'Yarn', 'npm'], + Virtualization: ['Docker'], + Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'], + npmGlobalPackages: ['verdaccio'] + }); // eslint-disable-next-line no-console console.log(data); process.exit(0); })(); -} else if (commander.args.length == 1 && !commander.config) { +} else if (commander.args.length == 1 && !commander.config) { // handling "verdaccio [config]" case if "-c" is missing in command line commander.config = commander.args.pop(); init(); @@ -94,10 +110,12 @@ if (commander.info) { init(); } -process.on('uncaughtException', function(err) { - logger.logger.fatal( { - err: err, - }, - 'uncaught exception, please report this\n@{err.stack}' ); +process.on('uncaughtException', function (err) { + logger.logger.fatal( + { + err: err + }, + 'uncaught exception, please report this\n@{err.stack}' + ); process.exit(255); }); diff --git a/src/lib/cli/utils.ts b/src/lib/cli/utils.ts index f3121505f..ebe8a383c 100644 --- a/src/lib/cli/utils.ts +++ b/src/lib/cli/utils.ts @@ -10,7 +10,7 @@ import { DEFAULT_PORT } from '../constants'; const logger = require('../logger'); -export const resolveConfigPath = function(storageLocation: string, file: string) { +export const resolveConfigPath = function (storageLocation: string, file: string) { return path.resolve(path.dirname(storageLocation), file); }; @@ -38,7 +38,7 @@ export function getListListenAddresses(argListen: string, configListen: any): an addresses = [DEFAULT_PORT]; } addresses = addresses - .map(function(addr): string { + .map(function (addr): string { const parsedAddr = parseAddress(addr); if (!parsedAddr) { diff --git a/src/lib/config-path.ts b/src/lib/config-path.ts index e53b178bc..68a25da83 100644 --- a/src/lib/config-path.ts +++ b/src/lib/config-path.ts @@ -1,8 +1,8 @@ import fs from 'fs'; -import _ from 'lodash'; import Path from 'path'; -import { logger } from './logger'; +import _ from 'lodash'; import mkdirp from 'mkdirp'; +import { logger } from './logger'; import { folderExists, fileExists } from './utils'; import { CHARACTER_ENCODING } from './constants'; @@ -16,7 +16,7 @@ const pkgJSON = require('../../package.json'); export type SetupDirectory = { path: string; - type: string + type: string; }; /** @@ -34,7 +34,9 @@ function findConfigFile(configPath: string): string { throw new Error('no configuration files can be processed'); } - const primaryConf: any = _.find(configPaths, (configLocation: any) => fileExists(configLocation.path)); + const primaryConf: any = _.find(configPaths, (configLocation: any) => + fileExists(configLocation.path) + ); if (_.isNil(primaryConf) === false) { return primaryConf.path; } @@ -69,7 +71,8 @@ function updateStorageLinks(configLocation, defaultConfig): string { // $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored, // If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used. // $FlowFixMe - let dataDir = process.env.XDG_DATA_HOME || Path.join(process.env.HOME as string, '.local', 'share'); + let dataDir = + process.env.XDG_DATA_HOME || Path.join(process.env.HOME as string, '.local', 'share'); if (folderExists(dataDir)) { dataDir = Path.resolve(Path.join(dataDir, pkgJSON.name, 'storage')); return defaultConfig.replace(/^storage: .\/storage$/m, `storage: ${dataDir}`); @@ -78,13 +81,17 @@ function updateStorageLinks(configLocation, defaultConfig): string { } function getConfigPaths(): SetupDirectory[] { - const listPaths: SetupDirectory[] = [getXDGDirectory(), getWindowsDirectory(), getRelativeDefaultDirectory(), getOldDirectory()].reduce( - function(acc, currentValue: any): SetupDirectory[] { - if (_.isUndefined(currentValue) === false) { - acc.push(currentValue); - } - return acc; - }, [] as SetupDirectory[]); + const listPaths: SetupDirectory[] = [ + getXDGDirectory(), + getWindowsDirectory(), + getRelativeDefaultDirectory(), + getOldDirectory() + ].reduce(function (acc, currentValue: any): SetupDirectory[] { + if (_.isUndefined(currentValue) === false) { + acc.push(currentValue); + } + return acc; + }, [] as SetupDirectory[]); return listPaths; } @@ -95,7 +102,7 @@ const getXDGDirectory = (): SetupDirectory | void => { if (XDGConfig && folderExists(XDGConfig)) { return { path: Path.join(XDGConfig, pkgJSON.name, CONFIG_FILE), - type: XDG, + type: XDG }; } }; @@ -106,7 +113,7 @@ const getWindowsDirectory = (): SetupDirectory | void => { if (process.platform === WIN32 && process.env.APPDATA && folderExists(process.env.APPDATA)) { return { path: Path.resolve(Path.join(process.env.APPDATA, pkgJSON.name, CONFIG_FILE)), - type: WIN, + type: WIN }; } }; @@ -114,14 +121,14 @@ const getWindowsDirectory = (): SetupDirectory | void => { const getRelativeDefaultDirectory = (): SetupDirectory => { return { path: Path.resolve(Path.join('.', pkgJSON.name, CONFIG_FILE)), - type: 'def', + type: 'def' }; }; const getOldDirectory = (): SetupDirectory => { return { path: Path.resolve(Path.join('.', CONFIG_FILE)), - type: 'old', + type: 'old' }; }; diff --git a/src/lib/config-utils.ts b/src/lib/config-utils.ts index 56d0c12f5..a91ff9909 100644 --- a/src/lib/config-utils.ts +++ b/src/lib/config-utils.ts @@ -3,21 +3,20 @@ * @flow */ -import _ from 'lodash'; import assert from 'assert'; +import _ from 'lodash'; import minimatch from 'minimatch'; -import { ErrorCode } from './utils'; - import { PackageList, UpLinksConfList } from '@verdaccio/types'; import { MatchedPackage, LegacyPackageList } from '../../types'; +import { ErrorCode } from './utils'; const BLACKLIST = { all: true, anonymous: true, undefined: true, owner: true, - none: true, + none: true }; /** @@ -47,7 +46,10 @@ export function normalizeUserList(oldFormat: any, newFormat: any): any { return _.flatten(result); } -export function uplinkSanityCheck(uplinks: UpLinksConfList, users: any = BLACKLIST): UpLinksConfList { +export function uplinkSanityCheck( + uplinks: UpLinksConfList, + users: any = BLACKLIST +): UpLinksConfList { const newUplinks = _.clone(uplinks); let newUsers = _.clone(users); @@ -65,7 +67,11 @@ export function uplinkSanityCheck(uplinks: UpLinksConfList, users: any = BLACKLI export function sanityCheckNames(item: string, users: any): any { assert( - item !== 'all' && item !== 'owner' && item !== 'anonymous' && item !== 'undefined' && item !== 'none', + item !== 'all' && + item !== 'owner' && + item !== 'anonymous' && + item !== 'undefined' && + item !== 'none', 'CONFIG: reserved uplink name: ' + item ); assert(!item.match(/\s/), 'CONFIG: invalid uplink name: ' + item); @@ -96,7 +102,7 @@ export function hasProxyTo(pkg: string, upLink: string, packages: PackageList): const matchedPkg: MatchedPackage = getMatchedPackagesSpec(pkg, packages); const proxyList = typeof matchedPkg !== 'undefined' ? matchedPkg.proxy : []; if (proxyList) { - return proxyList.some(curr => upLink === curr); + return proxyList.some((curr) => upLink === curr); } return false; @@ -124,11 +130,20 @@ export function normalisePackageAccess(packages: LegacyPackageList): LegacyPacka _.isObject(packages[pkg]) && _.isArray(packages[pkg]) === false, `CONFIG: bad "'${pkg}'" package description (object expected)` ); - normalizedPkgs[pkg].access = normalizeUserList(packages[pkg].allow_access, packages[pkg].access); + normalizedPkgs[pkg].access = normalizeUserList( + packages[pkg].allow_access, + packages[pkg].access + ); delete normalizedPkgs[pkg].allow_access; - normalizedPkgs[pkg].publish = normalizeUserList(packages[pkg].allow_publish, packages[pkg].publish); + normalizedPkgs[pkg].publish = normalizeUserList( + packages[pkg].allow_publish, + packages[pkg].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; // if unpublish is not defined, we set to false to fallback in publish access normalizedPkgs[pkg].unpublish = _.isUndefined(packages[pkg].unpublish) diff --git a/src/lib/config.ts b/src/lib/config.ts index 5a2011e7a..dc067da5f 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,14 +1,17 @@ -import _ from 'lodash'; import assert from 'assert'; - -import { generateRandomHexString } from './crypto-utils'; -import { getMatchedPackagesSpec, normalisePackageAccess, sanityCheckUplinksProps, uplinkSanityCheck } from './config-utils'; -import { getUserAgent, isObject } from './utils'; -import { APP_ERROR } from './constants'; +import _ from 'lodash'; import { PackageList, Config as AppConfig, Security, Logger } from '@verdaccio/types'; - import { MatchedPackage, StartUpConfig } from '../../types'; +import { generateRandomHexString } from './crypto-utils'; +import { + getMatchedPackagesSpec, + normalisePackageAccess, + sanityCheckUplinksProps, + uplinkSanityCheck +} from './config-utils'; +import { getUserAgent, isObject } from './utils'; +import { APP_ERROR } from './constants'; const LoggerApi = require('./logger'); const strategicConfigProps = ['uplinks', 'packages']; @@ -54,7 +57,7 @@ class Config implements AppConfig { assert(_.isObject(config), APP_ERROR.CONFIG_NOT_VALID); // sanity check for strategic config properties - strategicConfigProps.forEach(function(x): void { + strategicConfigProps.forEach(function (x): void { if (self[x] == null) { self[x] = {}; } @@ -72,13 +75,11 @@ class Config implements AppConfig { this.packages = normalisePackageAccess(self.packages); // loading these from ENV if aren't in config - allowedEnvConfig.forEach( - (envConf): void => { - if (!(envConf in self)) { - self[envConf] = process.env[envConf] || process.env[envConf.toUpperCase()]; - } + allowedEnvConfig.forEach((envConf): void => { + if (!(envConf in self)) { + self[envConf] = process.env[envConf] || process.env[envConf.toUpperCase()]; } - ); + }); // unique identifier of self server (or a cluster), used to avoid loops // @ts-ignore diff --git a/src/lib/constants.ts b/src/lib/constants.ts index c0f65adce..96495fd19 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -39,22 +39,22 @@ export const HEADERS = { OCTET_STREAM: 'application/octet-stream; charset=utf-8', TEXT_CHARSET: 'text/plain; charset=utf-8', WWW_AUTH: 'WWW-Authenticate', - GZIP: 'gzip', + GZIP: 'gzip' }; export const CHARACTER_ENCODING = { - UTF8: 'utf8', + UTF8: 'utf8' }; export const HEADER_TYPE = { CONTENT_ENCODING: 'content-encoding', CONTENT_TYPE: 'content-type', CONTENT_LENGTH: 'content-length', - ACCEPT_ENCODING: 'accept-encoding', + ACCEPT_ENCODING: 'accept-encoding' }; export const ERROR_CODE = { - token_required: 'token is required', + token_required: 'token is required' }; export const TOKEN_BASIC = 'Basic'; @@ -69,7 +69,7 @@ export const ROLES = { $ANONYMOUS: '$anonymous', DEPRECATED_ALL: '@all', DEPRECATED_AUTH: '@authenticated', - DEPRECATED_ANONYMOUS: '@anonymous', + DEPRECATED_ANONYMOUS: '@anonymous' }; export const HTTP_STATUS = { @@ -87,7 +87,7 @@ export const HTTP_STATUS = { INTERNAL_ERROR: 500, NOT_IMPLEMENTED: 501, SERVICE_UNAVAILABLE: 503, - LOOP_DETECTED: 508, + LOOP_DETECTED: 508 }; export const API_MESSAGE = { @@ -100,14 +100,14 @@ export const API_MESSAGE = { TAG_UPDATED: 'tags updated', TAG_REMOVED: 'tag removed', TAG_ADDED: 'package tagged', - LOGGED_OUT: 'Logged out', + LOGGED_OUT: 'Logged out' }; export const SUPPORT_ERRORS = { PLUGIN_MISSING_INTERFACE: 'the plugin does not provide implementation of the requested feature', TFA_DISABLED: 'the two-factor authentication is not yet supported', STORAGE_NOT_IMPLEMENT: 'the storage does not support token saving', - PARAMETERS_NOT_VALID: 'the parameters are not valid', + PARAMETERS_NOT_VALID: 'the parameters are not valid' }; export const API_ERROR = { @@ -142,13 +142,13 @@ export const API_ERROR = { RESOURCE_UNAVAILABLE: 'resource unavailable', BAD_PACKAGE_DATA: 'bad incoming package data', USERNAME_PASSWORD_REQUIRED: 'username and password is required', - USERNAME_ALREADY_REGISTERED: 'username is already registered', + USERNAME_ALREADY_REGISTERED: 'username is already registered' }; export const APP_ERROR = { CONFIG_NOT_VALID: 'CONFIG: it does not look like a valid config file', PROFILE_ERROR: 'profile unexpected error', - PASSWORD_VALIDATION: 'not valid password', + PASSWORD_VALIDATION: 'not valid password' }; export const DEFAULT_NO_README = 'ERROR: No README data found!'; @@ -158,12 +158,12 @@ export const WEB_TITLE = 'Verdaccio'; export const PACKAGE_ACCESS = { SCOPE: '@*/*', - ALL: '**', + ALL: '**' }; export const STORAGE = { PACKAGE_FILE_NAME: 'package.json', FILE_EXIST_ERROR: 'EEXISTS', NO_SUCH_FILE_ERROR: 'ENOENT', - DEFAULT_REVISION: '0-0000000000000000', + DEFAULT_REVISION: '0-0000000000000000' }; diff --git a/src/lib/crypto-utils.ts b/src/lib/crypto-utils.ts index 42fedb0f5..21bd4167f 100644 --- a/src/lib/crypto-utils.ts +++ b/src/lib/crypto-utils.ts @@ -42,23 +42,25 @@ export function createTarballHash(): Hash { * @return {String} */ export function stringToMD5(data: Buffer | string): string { - return createHash('md5') - .update(data) - .digest('hex'); + return createHash('md5').update(data).digest('hex'); } export function generateRandomHexString(length = 8): string { return pseudoRandomBytes(length).toString('hex'); } -export async function signPayload(payload: RemoteUser, secretOrPrivateKey: string, options: JWTSignOptions): Promise { - return new Promise(function(resolve, reject): Promise { +export async function signPayload( + payload: RemoteUser, + secretOrPrivateKey: string, + options: JWTSignOptions +): Promise { + return new Promise(function (resolve, reject): Promise { return jwt.sign( payload, secretOrPrivateKey, { notBefore: '1', // Make sure the time will not rollback :) - ...options, + ...options }, (error, token) => (error ? reject(error) : resolve(token)) ); diff --git a/src/lib/local-storage.ts b/src/lib/local-storage.ts index 11d5a2dd7..e067ca6c8 100644 --- a/src/lib/local-storage.ts +++ b/src/lib/local-storage.ts @@ -1,12 +1,6 @@ import assert from 'assert'; import UrlNode from 'url'; import _ from 'lodash'; -import { ErrorCode, isObject, getLatestVersion, tagVersion, validateName } from './utils'; -import { generatePackageTemplate, normalizePackage, generateRevision, getLatestReadme, cleanUpReadme, normalizeContributors } from './storage-utils'; -import {API_ERROR, DIST_TAGS, HTTP_STATUS, STORAGE, SUPPORT_ERRORS, USERS} from './constants'; -import { createTarballHash } from './crypto-utils'; -import { prepareSearchPackage } from './storage-utils'; -import loadPlugin from '../lib/plugin-loader'; import LocalDatabase from '@verdaccio/local-storage'; import { UploadTarball, ReadTarball } from '@verdaccio/streams'; import { @@ -26,10 +20,24 @@ import { Author, CallbackAction, onSearchPackage, - onEndSearchPackage, StorageUpdateCallback, + onEndSearchPackage, + StorageUpdateCallback } from '@verdaccio/types'; -import { IStorage, StringValue } from '../../types'; import { VerdaccioError } from '@verdaccio/commons-api'; +import loadPlugin from '../lib/plugin-loader'; +import { IStorage, StringValue } from '../../types'; +import { ErrorCode, isObject, getLatestVersion, tagVersion, validateName } from './utils'; +import { + generatePackageTemplate, + normalizePackage, + generateRevision, + getLatestReadme, + cleanUpReadme, + normalizeContributors +} from './storage-utils'; +import { API_ERROR, DIST_TAGS, HTTP_STATUS, STORAGE, SUPPORT_ERRORS, USERS } from './constants'; +import { createTarballHash } from './crypto-utils'; +import { prepareSearchPackage } from './storage-utils'; /** * Implements Storage interface (same for storage.js, local-storage.js, up-storage.js). @@ -52,10 +60,13 @@ class LocalStorage implements IStorage { return callback(ErrorCode.getNotFound('this package cannot be added')); } - storage.createPackage(name, generatePackageTemplate(name), err => { + storage.createPackage(name, generatePackageTemplate(name), (err) => { // FIXME: it will be fixed here https://github.com/verdaccio/verdaccio/pull/1360 // @ts-ignore - if (_.isNull(err) === false && (err.code === STORAGE.FILE_EXIST_ERROR || err.code === HTTP_STATUS.CONFLICT)) { + if ( + _.isNull(err) === false && + (err.code === STORAGE.FILE_EXIST_ERROR || err.code === HTTP_STATUS.CONFLICT) + ) { return callback(ErrorCode.getConflict()); } @@ -95,7 +106,10 @@ class LocalStorage implements IStorage { this.storagePlugin.remove(name, (removeFailed: Error): void => { if (removeFailed) { // This will happen when database is locked - this.logger.debug({ name }, `[storage/removePackage] the database is locked, removed has failed for @{name}`); + this.logger.debug( + { name }, + `[storage/removePackage] the database is locked, removed has failed for @{name}` + ); return callback(ErrorCode.getBadData(removeFailed.message)); } @@ -150,7 +164,7 @@ class LocalStorage implements IStorage { if (_.isNil(packageLocalJson._distfiles[filename])) { const hash: DistFile = (packageLocalJson._distfiles[filename] = { url: version.dist.tarball, - sha: version.dist.shasum, + sha: version.dist.shasum }); /* eslint spaced-comment: 0 */ // $FlowFixMe @@ -165,7 +179,10 @@ class LocalStorage implements IStorage { } for (const tag in packageInfo[DIST_TAGS]) { - if (!packageLocalJson[DIST_TAGS][tag] || packageLocalJson[DIST_TAGS][tag] !== packageInfo[DIST_TAGS][tag]) { + if ( + !packageLocalJson[DIST_TAGS][tag] || + packageLocalJson[DIST_TAGS][tag] !== packageInfo[DIST_TAGS][tag] + ) { change = true; packageLocalJson[DIST_TAGS][tag] = packageInfo[DIST_TAGS][tag]; } @@ -192,7 +209,7 @@ class LocalStorage implements IStorage { if (change) { this.logger.debug({ name }, 'updating package @{name} info'); - this._writePackage(name, packageLocalJson, function(err): void { + this._writePackage(name, packageLocalJson, function (err): void { callback(err, packageLocalJson); }); } else { @@ -209,7 +226,13 @@ class LocalStorage implements IStorage { * @param {*} tag * @param {*} callback */ - public addVersion(name: string, version: string, metadata: Version, tag: StringValue, callback: CallbackAction): void { + public addVersion( + name: string, + version: string, + metadata: Version, + tag: StringValue, + callback: CallbackAction + ): void { this._updatePackage( name, (data, cb: Callback): void => { @@ -230,7 +253,10 @@ class LocalStorage implements IStorage { const tarball = metadata.dist.tarball.replace(/.*\//, ''); if (isObject(data._attachments[tarball])) { - if (_.isNil(data._attachments[tarball].shasum) === false && _.isNil(metadata.dist.shasum) === false) { + if ( + _.isNil(data._attachments[tarball].shasum) === false && + _.isNil(metadata.dist.shasum) === false + ) { if (data._attachments[tarball].shasum != metadata.dist.shasum) { const errorMessage = `shasum error, ${data._attachments[tarball].shasum} != ${metadata.dist.shasum}`; return cb(ErrorCode.getBadRequest(errorMessage)); @@ -327,13 +353,18 @@ class LocalStorage implements IStorage { * @param {*} callback * @return {Function} */ - public changePackage(name: string, incomingPkg: Package, revision: string | void, callback: Callback): void { + public changePackage( + name: string, + incomingPkg: Package, + revision: string | void, + callback: Callback + ): void { if (!isObject(incomingPkg.versions) || !isObject(incomingPkg[DIST_TAGS])) { - this.logger.debug({name}, `changePackage bad data for @{name}`); + this.logger.debug({ name }, `changePackage bad data for @{name}`); return callback(ErrorCode.getBadData()); } - this.logger.debug({name}, `changePackage udapting package for @{name}`); + this.logger.debug({ name }, `changePackage udapting package for @{name}`); this._updatePackage( name, (localData: Package, cb: CallbackAction): void => { @@ -355,10 +386,16 @@ class LocalStorage implements IStorage { const incomingDeprecated = incomingVersion.deprecated; if (incomingDeprecated != localData.versions[version].deprecated) { if (!incomingDeprecated) { - this.logger.info({ name: name, version: version }, 'undeprecating @{name}@@{version}'); + this.logger.info( + { name: name, version: version }, + 'undeprecating @{name}@@{version}' + ); delete localData.versions[version].deprecated; } else { - this.logger.info({ name: name, version: version }, 'deprecating @{name}@@{version}'); + this.logger.info( + { name: name, version: version }, + 'deprecating @{name}@@{version}' + ); localData.versions[version].deprecated = incomingDeprecated; } localData.time!.modified = new Date().toISOString(); @@ -370,7 +407,7 @@ class LocalStorage implements IStorage { localData[DIST_TAGS] = incomingPkg[DIST_TAGS]; cb(null); }, - function(err): void { + function (err): void { if (err) { return callback(err); } @@ -385,7 +422,12 @@ class LocalStorage implements IStorage { * @param {*} revision * @param {*} callback */ - public removeTarball(name: string, filename: string, revision: string, callback: CallbackAction): void { + public removeTarball( + name: string, + filename: string, + revision: string, + callback: CallbackAction + ): void { assert(validateName(filename)); this._updatePackage( @@ -426,10 +468,10 @@ class LocalStorage implements IStorage { const _transform = uploadStream._transform; const storage = this._getLocalStorage(name); - uploadStream.abort = function(): void {}; - uploadStream.done = function(): void {}; + uploadStream.abort = function (): void {}; + uploadStream.done = function (): void {}; - uploadStream._transform = function(data, ...args): void { + uploadStream._transform = function (data, ...args): void { shaOneHash.update(data); // measure the length for validation reasons length += data.length; @@ -455,15 +497,15 @@ class LocalStorage implements IStorage { const writeStream: IUploadTarball = storage.writeTarball(filename); - writeStream.on('error', err => { + writeStream.on('error', (err) => { // @ts-ignore if (err.code === STORAGE.FILE_EXIST_ERROR || err.code === HTTP_STATUS.CONFLICT) { uploadStream.emit('error', ErrorCode.getConflict()); uploadStream.abort(); - // @ts-ignore + // @ts-ignore } else if (err.code === STORAGE.NO_SUCH_FILE_ERROR || err.code === HTTP_STATUS.NOT_FOUND) { // check if package exists to throw an appropriate message - this.getPackageMetadata(name, function(_err: VerdaccioError, _res: Package): void { + this.getPackageMetadata(name, function (_err: VerdaccioError, _res: Package): void { if (_err) { uploadStream.emit('error', _err); } else { @@ -475,7 +517,7 @@ class LocalStorage implements IStorage { } }); - writeStream.on('open', function(): void { + writeStream.on('open', function (): void { // re-emitting open because it's handled in storage.js uploadStream.emit('open'); }); @@ -485,11 +527,11 @@ class LocalStorage implements IStorage { name, function updater(data, cb): void { data._attachments[filename] = { - shasum: shaOneHash.digest('hex'), + shasum: shaOneHash.digest('hex') }; cb(null); }, - function(err): void { + function (err): void { if (err) { uploadStream.emit('error', err); } else { @@ -499,11 +541,11 @@ class LocalStorage implements IStorage { ); }); - uploadStream.abort = function(): void { + uploadStream.abort = function (): void { writeStream.abort(); }; - uploadStream.done = function(): void { + uploadStream.done = function (): void { if (!length) { uploadStream.emit('error', ErrorCode.getBadData('refusing to accept zero-length file')); writeStream.abort(); @@ -561,13 +603,13 @@ class LocalStorage implements IStorage { const readTarballStream = storage.readTarball(filename); const e404 = ErrorCode.getNotFound; - stream.abort = function(): void { + stream.abort = function (): void { if (_.isNil(readTarballStream) === false) { readTarballStream.abort(); } }; - readTarballStream.on('error', function(err) { + readTarballStream.on('error', function (err) { // @ts-ignore if (err.code === STORAGE.NO_SUCH_FILE_ERROR || err.code === HTTP_STATUS.NOT_FOUND) { stream.emit('error', e404('no such file available')); @@ -576,11 +618,11 @@ class LocalStorage implements IStorage { } }); - readTarballStream.on('content-length', function(content): void { + readTarballStream.on('content-length', function (content): void { stream.emit('content-length', content); }); - readTarballStream.on('open', function(): void { + readTarballStream.on('open', function (): void { // re-emitting open because it's handled in storage.js stream.emit('open'); readTarballStream.pipe(stream); @@ -738,14 +780,24 @@ class LocalStorage implements IStorage { * @param {*} callback callback that gets invoked after it's all updated * @return {Function} */ - private _updatePackage(name: string, updateHandler: StorageUpdateCallback, callback: CallbackAction): void { + private _updatePackage( + name: string, + updateHandler: StorageUpdateCallback, + callback: CallbackAction + ): void { const storage: IPackageStorage = this._getLocalStorage(name); if (!storage) { return callback(ErrorCode.getNotFound()); } - storage.updatePackage(name, updateHandler, this._writePackage.bind(this), normalizePackage, callback); + storage.updatePackage( + name, + updateHandler, + this._writePackage.bind(this), + normalizePackage, + callback + ); } /** @@ -778,21 +830,24 @@ class LocalStorage implements IStorage { } private _deleteAttachments(storage: any, attachments: string[], callback: Callback): void { - this.logger.debug({l: attachments.length }, `[storage/_deleteAttachments] delete attachments total: @{l}`); - const unlinkNext = function(cb): void { + this.logger.debug( + { l: attachments.length }, + `[storage/_deleteAttachments] delete attachments total: @{l}` + ); + const unlinkNext = function (cb): void { if (_.isEmpty(attachments)) { return cb(); } const attachment = attachments.shift(); - storage.deletePackage(attachment, function(): void { + storage.deletePackage(attachment, function (): void { unlinkNext(cb); }); }; - unlinkNext(function(): void { + unlinkNext(function (): void { // try to unlink the directory, but ignore errors because it can fail - storage.removePackage(function(err): void { + storage.removePackage(function (err): void { callback(err); }); }); @@ -838,20 +893,27 @@ class LocalStorage implements IStorage { private _loadStorePlugin(): IPluginStorage | void { const plugin_params = { config: this.config, - logger: this.logger, + logger: this.logger }; - const plugins: IPluginStorage[] = loadPlugin>(this.config, this.config.store, plugin_params, (plugin): IPluginStorage => { - return plugin.getPackageStorage; - }); - + // eslint-disable-next-line max-len + const plugins: IPluginStorage[] = loadPlugin>( + this.config, + this.config.store, + plugin_params, + (plugin): IPluginStorage => { + return plugin.getPackageStorage; + } + ); return _.head(plugins); } public saveToken(token: Token): Promise { if (_.isFunction(this.storagePlugin.saveToken) === false) { - return Promise.reject(ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE)); + return Promise.reject( + ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE) + ); } return this.storagePlugin.saveToken(token); @@ -859,15 +921,19 @@ class LocalStorage implements IStorage { public deleteToken(user: string, tokenKey: string): Promise { if (_.isFunction(this.storagePlugin.deleteToken) === false) { - return Promise.reject(ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE)); + return Promise.reject( + ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE) + ); } return this.storagePlugin.deleteToken(user, tokenKey); } - public readTokens(filter: TokenFilter): Promise> { + public readTokens(filter: TokenFilter): Promise { if (_.isFunction(this.storagePlugin.readTokens) === false) { - return Promise.reject(ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE)); + return Promise.reject( + ErrorCode.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.PLUGIN_MISSING_INTERFACE) + ); } return this.storagePlugin.readTokens(filter); diff --git a/src/lib/logger.ts b/src/lib/logger.ts index 986dd5e27..e334af96e 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -1,8 +1,8 @@ /* eslint-disable */ -import {prettyTimestamped} from "./logger/format/pretty-timestamped"; -import {pretty} from "./logger/format/pretty"; -import {jsonFormat} from "./logger/format/json"; +import { prettyTimestamped } from './logger/format/pretty-timestamped'; +import { pretty } from './logger/format/pretty'; +import { jsonFormat } from './logger/format/json'; const cluster = require('cluster'); const Logger = require('bunyan'); @@ -49,7 +49,7 @@ function setup(logs, { logStart } = { logStart: true }) { logs = DEFAULT_LOGGER_CONF; } - logs.forEach(function(target: LoggerTarget) { + logs.forEach(function (target: LoggerTarget) { let level = target.level || 35; if (level === 'http') { level = 35; @@ -78,7 +78,7 @@ function setup(logs, { logStart } = { logStart: true }) { const rotateStream = { type: 'raw', level, - stream, + stream }; if (logStart) { @@ -94,8 +94,11 @@ function setup(logs, { logStart } = { logStart: true }) { let destinationIsTTY = false; if (target.type === 'file') { // destination stream - destination = require('fs').createWriteStream(target.path, { flags: 'a', encoding: 'utf8' }); - destination.on('error', function(err) { + destination = require('fs').createWriteStream(target.path, { + flags: 'a', + encoding: 'utf8' + }); + destination.on('error', function (err) { stream.emit('error', err); }); } else if (target.type === 'stdout' || target.type === 'stderr') { @@ -107,16 +110,16 @@ function setup(logs, { logStart } = { logStart: true }) { if (target.format === 'pretty') { // making fake stream for pretty printing - stream.write = obj => { + stream.write = (obj) => { destination.write(pretty(obj, destinationIsTTY)); }; } else if (target.format === 'pretty-timestamped') { // making fake stream for pretty printing - stream.write = obj => { + stream.write = (obj) => { destination.write(prettyTimestamped(obj, destinationIsTTY)); }; } else { - stream.write = obj => { + stream.write = (obj) => { destination.write(jsonFormat(obj, destinationIsTTY)); }; } @@ -127,7 +130,7 @@ function setup(logs, { logStart } = { logStart: true }) { // @ts-ignore level, // @ts-ignore - stream: stream, + stream: stream }); } }); @@ -139,8 +142,8 @@ function setup(logs, { logStart } = { logStart: true }) { serializers: { err: Logger.stdSerializers.err, req: Logger.stdSerializers.req, - res: Logger.stdSerializers.res, - }, + res: Logger.stdSerializers.res + } }); // In case of an empty log file, we ensure there is always something logged. This also helps see if the server @@ -149,7 +152,7 @@ function setup(logs, { logStart } = { logStart: true }) { logger.warn('Verdaccio started'); } - process.on('SIGUSR2', function() { + process.on('SIGUSR2', function () { // https://github.com/trentm/node-bunyan#stream-type-rotating-file if (logger) { /** diff --git a/src/lib/logger/format/json.ts b/src/lib/logger/format/json.ts index 6afbca590..2177843f6 100644 --- a/src/lib/logger/format/json.ts +++ b/src/lib/logger/format/json.ts @@ -1,10 +1,9 @@ - -import {fillInMsgTemplate} from "../formatter"; +import { fillInMsgTemplate } from '../formatter'; const Logger = require('bunyan'); export function jsonFormat(obj, hasColors): string { - const msg = fillInMsgTemplate(obj.msg, obj, hasColors); + const msg = fillInMsgTemplate(obj.msg, obj, hasColors); - return `${JSON.stringify({ ...obj, msg }, Logger.safeCycles())}\n`; + return `${JSON.stringify({ ...obj, msg }, Logger.safeCycles())}\n`; } diff --git a/src/lib/logger/format/pretty-timestamped.ts b/src/lib/logger/format/pretty-timestamped.ts index e7b0a9e44..6ee7fa64a 100644 --- a/src/lib/logger/format/pretty-timestamped.ts +++ b/src/lib/logger/format/pretty-timestamped.ts @@ -1,6 +1,6 @@ -import {formatLoggingDate} from "../utils"; -import {printMessage} from "../formatter"; +import { formatLoggingDate } from '../utils'; +import { printMessage } from '../formatter'; export function prettyTimestamped(obj, hasColors): string { - return `[${formatLoggingDate(obj.time)}] ${printMessage(obj.level, obj.msg, obj, hasColors)}\n`; + return `[${formatLoggingDate(obj.time)}] ${printMessage(obj.level, obj.msg, obj, hasColors)}\n`; } diff --git a/src/lib/logger/format/pretty.ts b/src/lib/logger/format/pretty.ts index c8f6875cc..e4bd27bb7 100644 --- a/src/lib/logger/format/pretty.ts +++ b/src/lib/logger/format/pretty.ts @@ -1,5 +1,5 @@ -import {printMessage} from "../formatter"; +import { printMessage } from '../formatter'; export function pretty(obj, hasColors): string { - return `${printMessage(obj.level, obj.msg, obj, hasColors)}\n`; + return `${printMessage(obj.level, obj.msg, obj, hasColors)}\n`; } diff --git a/src/lib/logger/formatter.ts b/src/lib/logger/formatter.ts index 792aea908..bc3d984ee 100644 --- a/src/lib/logger/formatter.ts +++ b/src/lib/logger/formatter.ts @@ -1,9 +1,9 @@ import { inspect } from 'util'; -import { isObject, pad } from '../utils'; import { red, green } from 'kleur'; import { white } from 'kleur'; -import {calculateLevel, levels, subsystems} from "./levels"; +import { isObject, pad } from '../utils'; +import { calculateLevel, levels, subsystems } from './levels'; let LEVEL_VALUE_MAX = 0; for (const l in levels) { @@ -36,7 +36,6 @@ export function printMessage(type, msg, templateObjects, hasColors) { export function fillInMsgTemplate(msg, obj: unknown, colors): string { return msg.replace(/@{(!?[$A-Za-z_][$0-9A-Za-z\._]*)}/g, (_, name): string => { - let str = obj; let is_error; if (name[0] === '!') { diff --git a/src/lib/logger/levels.ts b/src/lib/logger/levels.ts index 5517083d5..a2915e837 100644 --- a/src/lib/logger/levels.ts +++ b/src/lib/logger/levels.ts @@ -2,13 +2,13 @@ import { yellow, green, black, blue, red, magenta, cyan, white } from 'kleur'; // level to color export const levels = { - fatal: red, - error: red, - warn: yellow, - http: magenta, - info: cyan, - debug: green, - trace: white, + fatal: red, + error: red, + warn: yellow, + http: magenta, + info: cyan, + debug: green, + trace: white }; /** @@ -17,35 +17,35 @@ export const levels = { * @return {String} security level */ export function calculateLevel(x) { - switch (true) { - case x < 15: - return 'trace'; - case x < 25: - return 'debug'; - case x < 35: - return 'info'; - case x == 35: - return 'http'; - case x < 45: - return 'warn'; - case x < 55: - return 'error'; - default: - return 'fatal'; - } + switch (true) { + case x < 15: + return 'trace'; + case x < 25: + return 'debug'; + case x < 35: + return 'info'; + case x == 35: + return 'http'; + case x < 45: + return 'warn'; + case x < 55: + return 'error'; + default: + return 'fatal'; + } } export const subsystems = [ - { - in: green('<--'), - out: yellow('-->'), - fs: black('-=-'), - default: blue('---'), - }, - { - in: '<--', - out: '-->', - fs: '-=-', - default: '---', - }, + { + in: green('<--'), + out: yellow('-->'), + fs: black('-=-'), + default: blue('---') + }, + { + in: '<--', + out: '-->', + fs: '-=-', + default: '---' + } ]; diff --git a/src/lib/logger/utils.ts b/src/lib/logger/utils.ts index 251bce4c1..a61f53b1c 100644 --- a/src/lib/logger/utils.ts +++ b/src/lib/logger/utils.ts @@ -3,5 +3,5 @@ import dayjs from 'dayjs'; export const FORMAT_DATE = 'YYYY-MM-DD HH:mm:ss'; export function formatLoggingDate(time: string): string { - return dayjs(time).format(FORMAT_DATE); + return dayjs(time).format(FORMAT_DATE); } diff --git a/src/lib/metadata-utils.ts b/src/lib/metadata-utils.ts index 40dcf7e80..a10886ea5 100644 --- a/src/lib/metadata-utils.ts +++ b/src/lib/metadata-utils.ts @@ -5,9 +5,8 @@ import semver from 'semver'; import _ from 'lodash'; -import { DIST_TAGS } from './constants'; - import { Package } from '@verdaccio/types'; +import { DIST_TAGS } from './constants'; /** * Function gets a local info and an info from uplinks and tries to merge it diff --git a/src/lib/notify/index.ts b/src/lib/notify/index.ts index 0bd54f9bb..71f5701ac 100644 --- a/src/lib/notify/index.ts +++ b/src/lib/notify/index.ts @@ -1,13 +1,18 @@ import Handlebars from 'handlebars'; import _ from 'lodash'; -import { notifyRequest } from './notify-request'; import { OptionsWithUrl } from 'request'; import { Config, Package, RemoteUser } from '@verdaccio/types'; +import { notifyRequest } from './notify-request'; type TemplateMetadata = Package & { publishedPackage: string }; -export function handleNotify(metadata: Package, notifyEntry, remoteUser: RemoteUser, publishedPackage: string): Promise | void { +export function handleNotify( + metadata: Package, + notifyEntry, + remoteUser: RemoteUser, + publishedPackage: string +): Promise | void { let regex; if (metadata.name && notifyEntry.packagePattern) { regex = new RegExp(notifyEntry.packagePattern, notifyEntry.packagePatternFlags || ''); @@ -16,7 +21,7 @@ export function handleNotify(metadata: Package, notifyEntry, remoteUser: RemoteU } } - const template: HandlebarsTemplateDelegate = Handlebars.compile(notifyEntry.content); + const template = Handlebars.compile(notifyEntry.content); // don't override 'publisher' if package.json already has that /* eslint no-unused-vars: 0 */ /* eslint @typescript-eslint/no-unused-vars: 0 */ @@ -30,13 +35,13 @@ export function handleNotify(metadata: Package, notifyEntry, remoteUser: RemoteU const options: OptionsWithUrl = { body: content, - url: '', + url: '' }; // provides fallback support, it's accept an Object {} and Array of {} if (notifyEntry.headers && _.isArray(notifyEntry.headers)) { const header = {}; - notifyEntry.headers.map(function(item): void { + notifyEntry.headers.map(function (item): void { if (Object.is(item, item)) { for (const key in item) { /* eslint no-prototype-builtins: 0 */ @@ -60,17 +65,34 @@ export function handleNotify(metadata: Package, notifyEntry, remoteUser: RemoteU return notifyRequest(options, content); } -export function sendNotification(metadata: Package, notify: Notification, remoteUser: RemoteUser, publishedPackage: string): Promise { +export function sendNotification( + metadata: Package, + notify: any, + remoteUser: RemoteUser, + publishedPackage: string +): Promise { return handleNotify(metadata, notify, remoteUser, publishedPackage) as Promise; } -export function notify(metadata: Package, config: Config, remoteUser: RemoteUser, publishedPackage: string): Promise | void { +export function notify( + metadata: Package, + config: Config, + remoteUser: RemoteUser, + publishedPackage: string +): Promise | void { if (config.notify) { if (config.notify.content) { - return sendNotification(metadata, (config.notify as unknown) as Notification, remoteUser, publishedPackage); + return sendNotification( + metadata, + (config.notify as unknown) as any, + remoteUser, + publishedPackage + ); } // multiple notifications endpoints PR #108 - return Promise.all(_.map(config.notify, key => sendNotification(metadata, key, remoteUser, publishedPackage))); + return Promise.all( + _.map(config.notify, (key) => sendNotification(metadata, key, remoteUser, publishedPackage)) + ); } return Promise.resolve(); diff --git a/src/lib/notify/notify-request.ts b/src/lib/notify/notify-request.ts index a56725a9f..04ec5e8b0 100644 --- a/src/lib/notify/notify-request.ts +++ b/src/lib/notify/notify-request.ts @@ -1,24 +1,22 @@ import isNil from 'lodash/isNil'; -import { logger } from '../logger'; import request, { RequiredUriUrl } from 'request'; +import { logger } from '../logger'; import { HTTP_STATUS } from '../constants'; export function notifyRequest(options: RequiredUriUrl, content): Promise { - return new Promise( - (resolve, reject): void => { - request(options, function(err, response, body): void { - if (err || response.statusCode >= HTTP_STATUS.BAD_REQUEST) { - const errorMessage = isNil(err) ? response.body : err.message; - logger.error({ errorMessage }, 'notify service has thrown an error: @{errorMessage}'); - reject(errorMessage); - } - logger.info({ content }, 'A notification has been shipped: @{content}'); - if (isNil(body) === false) { - logger.debug({ body }, ' body: @{body}'); - resolve(body); - } - reject(Error('body is missing')); - }); - } - ); + return new Promise((resolve, reject): void => { + request(options, function (err, response, body): void { + if (err || response.statusCode >= HTTP_STATUS.BAD_REQUEST) { + const errorMessage = isNil(err) ? response.body : err.message; + logger.error({ errorMessage }, 'notify service has thrown an error: @{errorMessage}'); + reject(errorMessage); + } + logger.info({ content }, 'A notification has been shipped: @{content}'); + if (isNil(body) === false) { + logger.debug({ body }, ' body: @{body}'); + resolve(body); + } + reject(Error('body is missing')); + }); + }); } diff --git a/src/lib/plugin-loader.ts b/src/lib/plugin-loader.ts index 73620299a..dd96371c6 100644 --- a/src/lib/plugin-loader.ts +++ b/src/lib/plugin-loader.ts @@ -1,7 +1,7 @@ import Path from 'path'; import _ from 'lodash'; -import { logger } from './logger'; import { Config, IPlugin } from '@verdaccio/types'; +import { logger } from './logger'; import { MODULE_NOT_FOUND } from './constants'; /** @@ -96,31 +96,45 @@ export default function loadPlugin>( } if (plugin === null) { - logger.error({ content: pluginId, prefix }, 'plugin not found. try npm install @{prefix}-@{content}'); + logger.error( + { content: pluginId, prefix }, + 'plugin not found. try npm install @{prefix}-@{content}' + ); throw Error(` ${prefix}-${pluginId} plugin not found. try "npm install ${prefix}-${pluginId}"`); } if (!isValid(plugin)) { - logger.error({ content: pluginId }, "@{prefix}-@{content} plugin does not have the right code structure"); + logger.error( + { content: pluginId }, + '@{prefix}-@{content} plugin does not have the right code structure' + ); throw Error(`"${pluginId}" plugin does not have the right code structure`); } /* eslint new-cap:off */ - try { - plugin = isES6(plugin) ? new plugin.default(mergeConfig(config, pluginConfigs[pluginId]), params) : plugin(pluginConfigs[pluginId], params); - } catch (error) { - plugin = null; - logger.error({ error, pluginId }, "error loading a plugin @{pluginId}: @{error}"); - } + try { + plugin = isES6(plugin) + ? new plugin.default(mergeConfig(config, pluginConfigs[pluginId]), params) + : plugin(pluginConfigs[pluginId], params); + } catch (error) { + plugin = null; + logger.error({ error, pluginId }, 'error loading a plugin @{pluginId}: @{error}'); + } /* eslint new-cap:off */ if (plugin === null || !sanityCheck(plugin)) { - logger.error({ content: pluginId, prefix }, "@{prefix}-@{content} doesn't look like a valid plugin"); + logger.error( + { content: pluginId, prefix }, + "@{prefix}-@{content} doesn't look like a valid plugin" + ); throw Error(`sanity check has failed, "${pluginId}" is not a valid plugin`); } - logger.warn({ content: pluginId, prefix }, 'Plugin successfully loaded: @{prefix}-@{content}'); + logger.warn( + { content: pluginId, prefix }, + 'Plugin successfully loaded: @{prefix}-@{content}' + ); return plugin; } ); diff --git a/src/lib/search.ts b/src/lib/search.ts index f0b538c41..2816f3193 100644 --- a/src/lib/search.ts +++ b/src/lib/search.ts @@ -15,7 +15,7 @@ class Search implements IWebSearch { * Constructor. */ public constructor() { - this.index = lunrMutable(function(): void { + this.index = lunrMutable(function (): void { // FIXME: there is no types for this library /* eslint no-invalid-this:off */ // @ts-ignore @@ -43,11 +43,13 @@ class Search implements IWebSearch { public query(query: string): any[] { const localStorage = this.storage.localStorage as IStorage; - return query === '*' ? localStorage.storagePlugin.get((items): any => { - items.map(function(pkg): any { - return { ref: pkg, score: 1 }; - }); - }) : this.index.search(`*${query}*`); + return query === '*' + ? localStorage.storagePlugin.get((items): any => { + items.map(function (pkg): any { + return { ref: pkg, score: 1 }; + }); + }) + : this.index.search(`*${query}*`); } /** @@ -61,7 +63,7 @@ class Search implements IWebSearch { description: pkg.description, version: `v${pkg.version}`, keywords: pkg.keywords, - author: pkg._npmUser ? pkg._npmUser.name : '???', + author: pkg._npmUser ? pkg._npmUser.name : '???' }); } diff --git a/src/lib/storage-utils.ts b/src/lib/storage-utils.ts index 6cb2eea74..0ca82f5c6 100644 --- a/src/lib/storage-utils.ts +++ b/src/lib/storage-utils.ts @@ -1,10 +1,10 @@ import _ from 'lodash'; +import { Package, Version, Author } from '@verdaccio/types'; +import { generateRandomHexString } from '../lib/crypto-utils'; +import { IStorage } from '../../types'; import { ErrorCode, isObject, normalizeDistTags, semverSort } from './utils'; import Search from './search'; -import { generateRandomHexString } from '../lib/crypto-utils'; -import { Package, Version, Author } from '@verdaccio/types'; -import { IStorage } from '../../types'; import { API_ERROR, HTTP_STATUS, DIST_TAGS, USERS, STORAGE } from './constants'; export function generatePackageTemplate(name: string): Package { @@ -18,7 +18,7 @@ export function generatePackageTemplate(name: string): Package { _uplinks: {}, _distfiles: {}, _attachments: {}, - _rev: '', + _rev: '' }; } @@ -29,15 +29,13 @@ export function generatePackageTemplate(name: string): Package { export function normalizePackage(pkg: Package): Package { const pkgProperties = ['versions', 'dist-tags', '_distfiles', '_attachments', '_uplinks', 'time']; - pkgProperties.forEach( - (key): void => { - const pkgProp = pkg[key]; + pkgProperties.forEach((key): void => { + const pkgProp = pkg[key]; - if (_.isNil(pkgProp) || isObject(pkgProp) === false) { - pkg[key] = {}; - } + if (_.isNil(pkgProp) || isObject(pkgProp) === false) { + pkg[key] = {}; } - ); + }); if (_.isString(pkg._rev) === false) { pkg._rev = STORAGE.DEFAULT_REVISION; @@ -71,7 +69,7 @@ export function getLatestReadme(pkg: Package): string { // In case of empty readme - trying to get ANY readme in the following order: 'next','beta','alpha','test','dev','canary' const readmeDistTagsPriority = ['next', 'beta', 'alpha', 'test', 'dev', 'canary']; - readmeDistTagsPriority.map(function(tag): string | void { + readmeDistTagsPriority.map(function (tag): string | void { if (readme) { return readme; } @@ -99,15 +97,24 @@ export function normalizeContributors(contributors: Author[]): Author[] { } else if (_.isString(contributors)) { return [ { - name: contributors, - }, + name: contributors + } ]; } return contributors; } -export const WHITELIST = ['_rev', 'name', 'versions', 'dist-tags', 'readme', 'time', '_id', 'users']; +export const WHITELIST = [ + '_rev', + 'name', + 'versions', + 'dist-tags', + 'readme', + 'time', + '_id', + 'users' +]; export function cleanUpLinksRef(keepUpLinkData: boolean, result: Package): Package { const propertyToKeep = [...WHITELIST]; @@ -131,80 +138,66 @@ export function cleanUpLinksRef(keepUpLinkData: boolean, result: Package): Packa * @param {*} localStorage */ export function checkPackageLocal(name: string, localStorage: IStorage): Promise { - return new Promise( - (resolve, reject): void => { - localStorage.getPackageMetadata( - name, - (err, results): void => { - if (!_.isNil(err) && err.status !== HTTP_STATUS.NOT_FOUND) { - return reject(err); - } - if (results) { - return reject(ErrorCode.getConflict(API_ERROR.PACKAGE_EXIST)); - } - return resolve(); - } - ); - } - ); + return new Promise((resolve, reject): void => { + localStorage.getPackageMetadata(name, (err, results): void => { + if (!_.isNil(err) && err.status !== HTTP_STATUS.NOT_FOUND) { + return reject(err); + } + if (results) { + return reject(ErrorCode.getConflict(API_ERROR.PACKAGE_EXIST)); + } + return resolve(); + }); + }); } export function publishPackage(name: string, metadata: any, localStorage: IStorage): Promise { - return new Promise( - (resolve, reject): void => { - localStorage.addPackage( - name, - metadata, - (err, latest): void => { - if (!_.isNull(err)) { - return reject(err); - } else if (!_.isUndefined(latest)) { - Search.add(latest); - } - return resolve(); - } - ); - } - ); + return new Promise((resolve, reject): void => { + localStorage.addPackage(name, metadata, (err, latest): void => { + if (!_.isNull(err)) { + return reject(err); + } else if (!_.isUndefined(latest)) { + Search.add(latest); + } + return resolve(); + }); + }); } -export function checkPackageRemote(name: string, isAllowPublishOffline: boolean, syncMetadata: Function): Promise { - return new Promise( - (resolve, reject): void => { - syncMetadata( - name, - null, - {}, - (err, packageJsonLocal, upLinksErrors): void => { - // something weird - if (err && err.status !== HTTP_STATUS.NOT_FOUND) { - return reject(err); - } +export function checkPackageRemote( + name: string, + isAllowPublishOffline: boolean, + syncMetadata: Function +): Promise { + return new Promise((resolve, reject): void => { + syncMetadata(name, null, {}, (err, packageJsonLocal, upLinksErrors): void => { + // something weird + if (err && err.status !== HTTP_STATUS.NOT_FOUND) { + return reject(err); + } - // checking package exist already - if (_.isNil(packageJsonLocal) === false) { - return reject(ErrorCode.getConflict(API_ERROR.PACKAGE_EXIST)); - } + // checking package exist already + if (_.isNil(packageJsonLocal) === false) { + return reject(ErrorCode.getConflict(API_ERROR.PACKAGE_EXIST)); + } - for (let errorItem = 0; errorItem < upLinksErrors.length; errorItem++) { - // checking error - // if uplink fails with a status other than 404, we report failure - if (_.isNil(upLinksErrors[errorItem][0]) === false) { - if (upLinksErrors[errorItem][0].status !== HTTP_STATUS.NOT_FOUND) { - if (isAllowPublishOffline) { - return resolve(); - } - - return reject(ErrorCode.getServiceUnavailable(API_ERROR.UPLINK_OFFLINE_PUBLISH)); - } + for (let errorItem = 0; errorItem < upLinksErrors.length; errorItem++) { + // checking error + // if uplink fails with a status other than 404, we report failure + if (_.isNil(upLinksErrors[errorItem][0]) === false) { + if (upLinksErrors[errorItem][0].status !== HTTP_STATUS.NOT_FOUND) { + if (isAllowPublishOffline) { + return resolve(); } - } - return resolve(); + return reject(ErrorCode.getServiceUnavailable(API_ERROR.UPLINK_OFFLINE_PUBLISH)); + } } - ); - } - ); + } + + return resolve(); + }); + }); } export function mergeUplinkTimeIntoLocal(localMetadata: Package, remoteMetadata: Package): any { @@ -218,7 +211,8 @@ export function mergeUplinkTimeIntoLocal(localMetadata: Package, remoteMetadata: export function prepareSearchPackage(data: Package, time: unknown): any { const listVersions: string[] = Object.keys(data.versions); const versions: string[] = semverSort(listVersions); - const latest: string | undefined = data[DIST_TAGS] && data[DIST_TAGS].latest ? data[DIST_TAGS].latest : versions.pop(); + const latest: string | undefined = + data[DIST_TAGS] && data[DIST_TAGS].latest ? data[DIST_TAGS].latest : versions.pop(); if (latest && data.versions[latest]) { const version: Version = data.versions[latest]; @@ -236,9 +230,9 @@ export function prepareSearchPackage(data: Package, time: unknown): any { bugs: version.bugs, license: version.license, time: { - modified: time, + modified: time }, - versions, + versions }; return pkg; diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 955206060..d3b71feea 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -1,22 +1,49 @@ -import _ from 'lodash'; import assert from 'assert'; -import async, { AsyncResultArrayCallback } from 'async'; import Stream from 'stream'; +import _ from 'lodash'; +import async, { AsyncResultArrayCallback } from 'async'; +import { ReadTarball } from '@verdaccio/streams'; +import { + IReadTarball, + IUploadTarball, + Versions, + Package, + Config, + MergeTags, + Version, + DistFile, + Callback, + Logger +} from '@verdaccio/types'; +import { GenericBody, TokenFilter, Token } from '@verdaccio/types'; +import { VerdaccioError } from '@verdaccio/commons-api'; +import { + IStorage, + IProxy, + IStorageHandler, + ProxyList, + StringValue, + IGetPackageOptions, + ISyncUplinks, + IPluginFilters +} from '../../types'; +import { logger } from '../lib/logger'; import ProxyStorage from './up-storage'; import Search from './search'; import { API_ERROR, HTTP_STATUS, DIST_TAGS } from './constants'; import LocalStorage from './local-storage'; -import { ReadTarball } from '@verdaccio/streams'; -import { checkPackageLocal, publishPackage, checkPackageRemote, cleanUpLinksRef, mergeUplinkTimeIntoLocal, generatePackageTemplate } from './storage-utils'; +import { + checkPackageLocal, + publishPackage, + checkPackageRemote, + cleanUpLinksRef, + mergeUplinkTimeIntoLocal, + generatePackageTemplate +} from './storage-utils'; import { setupUpLinks, updateVersionsHiddenUpLink } from './uplink-util'; import { mergeVersions } from './metadata-utils'; import { ErrorCode, normalizeDistTags, validateMetadata, isObject } from './utils'; -import { IStorage, IProxy, IStorageHandler, ProxyList, StringValue, IGetPackageOptions, ISyncUplinks, IPluginFilters } from '../../types'; -import { IReadTarball, IUploadTarball, Versions, Package, Config, MergeTags, Version, DistFile, Callback, Logger } from '@verdaccio/types'; import { hasProxyTo } from './config-utils'; -import { logger } from '../lib/logger'; -import { GenericBody, TokenFilter, Token } from '@verdaccio/types'; -import { VerdaccioError } from '@verdaccio/commons-api'; class Storage implements IStorageHandler { public localStorage: IStorage; @@ -50,7 +77,11 @@ class Storage implements IStorageHandler { public async addPackage(name: string, metadata: any, callback: Function): Promise { try { await checkPackageLocal(name, this.localStorage); - await checkPackageRemote(name, this._isAllowPublishOffline(), this._syncUplinksMetadata.bind(this)); + await checkPackageRemote( + name, + this._isAllowPublishOffline(), + this._syncUplinksMetadata.bind(this) + ); await publishPackage(name, metadata, this.localStorage as IStorage); callback(); } catch (err) { @@ -59,10 +90,14 @@ class Storage implements IStorageHandler { } private _isAllowPublishOffline(): boolean { - return typeof this.config.publish !== 'undefined' && _.isBoolean(this.config.publish.allow_offline) && this.config.publish.allow_offline; + return ( + typeof this.config.publish !== 'undefined' && + _.isBoolean(this.config.publish.allow_offline) && + this.config.publish.allow_offline + ); } - public readTokens(filter: TokenFilter): Promise> { + public readTokens(filter: TokenFilter): Promise { return this.localStorage.readTokens(filter); } @@ -78,7 +113,13 @@ class Storage implements IStorageHandler { * Add a new version of package {name} to a system Used storages: local (write) */ - public addVersion(name: string, version: string, metadata: Version, tag: StringValue, callback: Callback): void { + public addVersion( + name: string, + version: string, + metadata: Version, + tag: StringValue, + callback: Callback + ): void { this.localStorage.addVersion(name, version, metadata, tag, callback); } @@ -95,7 +136,12 @@ class Storage implements IStorageHandler { Function changes a package info from local storage and all uplinks with write access./ Used storages: local (write) */ - public changePackage(name: string, metadata: Package, revision: string, callback: Callback): void { + public changePackage( + name: string, + metadata: Package, + revision: string, + callback: Callback + ): void { this.localStorage.changePackage(name, metadata, revision, callback); } @@ -139,7 +185,7 @@ class Storage implements IStorageHandler { */ public getTarball(name: string, filename: string): IReadTarball { const readStream = new ReadTarball({}); - readStream.abort = function() {}; + readStream.abort = function () {}; const self = this; @@ -150,48 +196,37 @@ class Storage implements IStorageHandler { // flow: should be IReadTarball let localStream: any = self.localStorage.getTarball(name, filename); let isOpen = false; - localStream.on( - 'error', - (err): any => { - if (isOpen || err.status !== HTTP_STATUS.NOT_FOUND) { - return readStream.emit('error', err); - } - - // local reported 404 - const err404 = err; - localStream.abort(); - localStream = null; // we force for garbage collector - self.localStorage.getPackageMetadata( - name, - (err, info: Package): void => { - if (_.isNil(err) && info._distfiles && _.isNil(info._distfiles[filename]) === false) { - // information about this file exists locally - serveFile(info._distfiles[filename]); - } else { - // we know nothing about this file, trying to get information elsewhere - self._syncUplinksMetadata( - name, - info, - {}, - (err, info: Package): any => { - if (_.isNil(err) === false) { - return readStream.emit('error', err); - } - if (_.isNil(info._distfiles) || _.isNil(info._distfiles[filename])) { - return readStream.emit('error', err404); - } - serveFile(info._distfiles[filename]); - } - ); - } - } - ); + localStream.on('error', (err): any => { + if (isOpen || err.status !== HTTP_STATUS.NOT_FOUND) { + return readStream.emit('error', err); } - ); - localStream.on('content-length', function(v): void { + + // local reported 404 + const err404 = err; + localStream.abort(); + localStream = null; // we force for garbage collector + self.localStorage.getPackageMetadata(name, (err, info: Package): void => { + if (_.isNil(err) && info._distfiles && _.isNil(info._distfiles[filename]) === false) { + // information about this file exists locally + serveFile(info._distfiles[filename]); + } else { + // we know nothing about this file, trying to get information elsewhere + self._syncUplinksMetadata(name, info, {}, (err, info: Package): any => { + if (_.isNil(err) === false) { + return readStream.emit('error', err); + } + if (_.isNil(info._distfiles) || _.isNil(info._distfiles[filename])) { + return readStream.emit('error', err404); + } + serveFile(info._distfiles[filename]); + }); + } + }); + }); + localStream.on('content-length', function (v): void { readStream.emit('content-length', v); }); - localStream.on('open', function(): void { + localStream.on('open', function (): void { isOpen = true; localStream.pipe(readStream); }); @@ -215,7 +250,7 @@ class Storage implements IStorageHandler { { url: file.url, cache: true, - _autogenerated: true, + _autogenerated: true }, self.config ); @@ -226,24 +261,24 @@ class Storage implements IStorageHandler { savestream = self.localStorage.addTarball(name, filename); } - let on_open = function(): void { + let on_open = function (): void { // prevent it from being called twice - on_open = function() {}; + on_open = function () {}; const rstream2 = uplink.fetchTarball(file.url); - rstream2.on('error', function(err): void { + rstream2.on('error', function (err): void { if (savestream) { savestream.abort(); } savestream = null; readStream.emit('error', err); }); - rstream2.on('end', function(): void { + rstream2.on('end', function (): void { if (savestream) { savestream.done(); } }); - rstream2.on('content-length', function(v): void { + rstream2.on('content-length', function (v): void { readStream.emit('content-length', v); if (savestream) { savestream.emit('content-length', v); @@ -256,12 +291,15 @@ class Storage implements IStorageHandler { }; if (savestream) { - savestream.on('open', function(): void { + savestream.on('open', function (): void { on_open(); }); - savestream.on('error', function(err): void { - self.logger.warn({ err: err, fileName: file }, 'error saving file @{fileName}: @{err.message}\n@{err.stack}'); + savestream.on('error', function (err): void { + self.logger.warn( + { err: err, fileName: file }, + 'error saving file @{fileName}: @{err.message}\n@{err.stack}' + ); if (savestream) { savestream.abort(); } @@ -288,19 +326,17 @@ class Storage implements IStorageHandler { * @property {function} options.callback Callback for receive data */ public getPackage(options: IGetPackageOptions): void { - this.localStorage.getPackageMetadata( - options.name, - (err, data): void => { - if (err && (!err.status || err.status >= HTTP_STATUS.INTERNAL_ERROR)) { - // report internal errors right away - return options.callback(err); - } + this.localStorage.getPackageMetadata(options.name, (err, data): void => { + if (err && (!err.status || err.status >= HTTP_STATUS.INTERNAL_ERROR)) { + // report internal errors right away + return options.callback(err); + } - this._syncUplinksMetadata(options.name, data, { req: options.req, uplinksLook: options.uplinksLook }, function getPackageSynUpLinksCallback( - err, - result: Package, - uplinkErrors - ): void { + this._syncUplinksMetadata( + options.name, + data, + { req: options.req, uplinksLook: options.uplinksLook }, + function getPackageSynUpLinksCallback(err, result: Package, uplinkErrors): void { if (err) { return options.callback(err); } @@ -311,9 +347,9 @@ class Storage implements IStorageHandler { result._attachments = {}; options.callback(null, result, uplinkErrors); - }); - } - ); + } + ); + }); } /** @@ -335,7 +371,7 @@ class Storage implements IStorageHandler { async.eachSeries( Object.keys(this.uplinks), - function(up_name, cb): void { + function (up_name, cb): void { // shortcut: if `local=1` is supplied, don't call uplinks if (options.req.query.local !== undefined) { return cb(); @@ -343,40 +379,34 @@ class Storage implements IStorageHandler { // search by keyword for each uplink const lstream: IUploadTarball = self.uplinks[up_name].search(options); // join streams - lstream.pipe( - stream, - { end: false } - ); - lstream.on('error', function(err): void { + lstream.pipe(stream, { end: false }); + lstream.on('error', function (err): void { self.logger.error({ err: err }, 'uplink error: @{err.message}'); cb(); - cb = function(): void {}; + cb = function (): void {}; }); - lstream.on('end', function(): void { + lstream.on('end', function (): void { cb(); - cb = function(): void {}; + cb = function (): void {}; }); - stream.abort = function(): void { + stream.abort = function (): void { if (lstream.abort) { lstream.abort(); } cb(); - cb = function(): void {}; + cb = function (): void {}; }; }, // executed after all series - function(): void { + function (): void { // attach a local search results const lstream: IReadTarball = self.localStorage.search(startkey, options); - stream.abort = function(): void { + stream.abort = function (): void { lstream.abort(); }; - lstream.pipe( - stream, - { end: true } - ); - lstream.on('error', function(err: VerdaccioError): void { + lstream.pipe(stream, { end: true }); + lstream.on('error', function (err: VerdaccioError): void { self.logger.error({ err: err }, 'search error: @{err.message}'); stream.end(); }); @@ -392,15 +422,16 @@ class Storage implements IStorageHandler { */ public getLocalDatabase(callback: Callback): void { const self = this; - this.localStorage.storagePlugin.get( - (err, locals): void => { - if (err) { - callback(err); - } + this.localStorage.storagePlugin.get((err, locals): void => { + if (err) { + callback(err); + } - const packages: Version[] = []; - const getPackage = function(itemPkg): void { - self.localStorage.getPackageMetadata(locals[itemPkg], function(err, pkgMetadata: Package): void { + const packages: Version[] = []; + const getPackage = function (itemPkg): void { + self.localStorage.getPackageMetadata( + locals[itemPkg], + function (err, pkgMetadata: Package): void { if (_.isNil(err)) { const latest = pkgMetadata[DIST_TAGS].latest; if (latest && pkgMetadata.versions[latest]) { @@ -416,7 +447,10 @@ class Storage implements IStorageHandler { packages.push(version); } else { - self.logger.warn({ package: locals[itemPkg] }, 'package @{package} does not have a "latest" tag?'); + self.logger.warn( + { package: locals[itemPkg] }, + 'package @{package} does not have a "latest" tag?' + ); } } @@ -425,16 +459,16 @@ class Storage implements IStorageHandler { } else { getPackage(itemPkg + 1); } - }); - }; + } + ); + }; - if (locals.length) { - getPackage(0); - } else { - callback(null, []); - } + if (locals.length) { + getPackage(0); + } else { + callback(null, []); } - ); + }); } /** @@ -442,7 +476,12 @@ class Storage implements IStorageHandler { if package is available locally, it MUST be provided in pkginfo returns callback(err, result, uplink_errors) */ - public _syncUplinksMetadata(name: string, packageInfo: Package, options: ISyncUplinks, callback: Callback): void { + public _syncUplinksMetadata( + name: string, + packageInfo: Package, + options: ISyncUplinks, + callback: Callback + ): void { let found = true; const self = this; const upLinks: IProxy[] = []; @@ -475,59 +514,55 @@ class Storage implements IStorageHandler { _options.etag = upLinkMeta.etag; } - upLink.getRemoteMetadata( - name, - _options, - (err, upLinkResponse, eTag): void => { - if (err && err.remoteStatus === 304) { - upLinkMeta.fetched = Date.now(); - } - - if (err || !upLinkResponse) { - return cb(null, [err || ErrorCode.getInternalError('no data')]); - } - - try { - validateMetadata(upLinkResponse, name); - } catch (err) { - self.logger.error( - { - sub: 'out', - err: err, - }, - 'package.json validating error @{!err.message}\n@{err.stack}' - ); - return cb(null, [err]); - } - - packageInfo._uplinks[upLink.upname] = { - etag: eTag, - fetched: Date.now(), - }; - - packageInfo.time = mergeUplinkTimeIntoLocal(packageInfo, upLinkResponse); - - updateVersionsHiddenUpLink(upLinkResponse.versions, upLink); - - try { - mergeVersions(packageInfo, upLinkResponse); - } catch (err) { - self.logger.error( - { - sub: 'out', - err: err, - }, - 'package.json parsing error @{!err.message}\n@{err.stack}' - ); - return cb(null, [err]); - } - - // if we got to this point, assume that the correct package exists - // on the uplink - found = true; - cb(); + upLink.getRemoteMetadata(name, _options, (err, upLinkResponse, eTag): void => { + if (err && err.remoteStatus === 304) { + upLinkMeta.fetched = Date.now(); } - ); + + if (err || !upLinkResponse) { + return cb(null, [err || ErrorCode.getInternalError('no data')]); + } + + try { + validateMetadata(upLinkResponse, name); + } catch (err) { + self.logger.error( + { + sub: 'out', + err: err + }, + 'package.json validating error @{!err.message}\n@{err.stack}' + ); + return cb(null, [err]); + } + + packageInfo._uplinks[upLink.upname] = { + etag: eTag, + fetched: Date.now() + }; + + packageInfo.time = mergeUplinkTimeIntoLocal(packageInfo, upLinkResponse); + + updateVersionsHiddenUpLink(upLinkResponse.versions, upLink); + + try { + mergeVersions(packageInfo, upLinkResponse); + } catch (err) { + self.logger.error( + { + sub: 'out', + err: err + }, + 'package.json parsing error @{!err.message}\n@{err.stack}' + ); + return cb(null, [err]); + } + + // if we got to this point, assume that the correct package exists + // on the uplink + found = true; + cb(); + }); }, // @ts-ignore (err: Error, upLinksErrors: any): AsyncResultArrayCallback => { diff --git a/src/lib/up-storage.ts b/src/lib/up-storage.ts index 81c205e94..164529400 100644 --- a/src/lib/up-storage.ts +++ b/src/lib/up-storage.ts @@ -1,17 +1,26 @@ import zlib from 'zlib'; +import Stream, { Readable } from 'stream'; +import URL, { UrlWithStringQuery } from 'url'; import JSONStream from 'JSONStream'; import _ from 'lodash'; import request from 'request'; -import Stream, { Readable } from 'stream'; -import URL, {UrlWithStringQuery} from 'url'; -import { parseInterval, isObject, ErrorCode, buildToken } from './utils'; import { ReadTarball } from '@verdaccio/streams'; -import { ERROR_CODE, TOKEN_BASIC, TOKEN_BEARER, HEADERS, HTTP_STATUS, API_ERROR, HEADER_TYPE, CHARACTER_ENCODING } from './constants'; import { Config, Callback, Headers, Logger, Package } from '@verdaccio/types'; import { IProxy, UpLinkConfLocal } from '../../types'; +import { parseInterval, isObject, ErrorCode, buildToken } from './utils'; +import { + ERROR_CODE, + TOKEN_BASIC, + TOKEN_BEARER, + HEADERS, + HTTP_STATUS, + API_ERROR, + HEADER_TYPE, + CHARACTER_ENCODING +} from './constants'; const LoggerApi = require('./logger'); -const encode = function(thing): string { +const encode = function (thing): string { return encodeURIComponent(thing).replace(/^%40/, '@'); }; @@ -77,7 +86,7 @@ class ProxyStorage implements IProxy { 'Too big timeout value: ' + this.config.timeout, 'We changed time format to nginx-like one', '(see http://nginx.org/en/docs/syntax.html)', - 'so please update your config accordingly', + 'so please update your config accordingly' ].join('\n') ); } @@ -107,16 +116,16 @@ class ProxyStorage implements IProxy { if (this._statusCheck() === false) { const streamRead = new Stream.Readable(); - process.nextTick(function(): void { + process.nextTick(function (): void { if (cb) { cb(ErrorCode.getInternalError(API_ERROR.UPLINK_OFFLINE)); } streamRead.emit('error', ErrorCode.getInternalError(API_ERROR.UPLINK_OFFLINE)); }); // $FlowFixMe - streamRead._read = function(): void {}; + streamRead._read = function (): void {}; // preventing 'Uncaught, unspecified "error" event' - streamRead.on('error', function(): void {}); + streamRead.on('error', function (): void {}); return streamRead; } @@ -133,7 +142,7 @@ class ProxyStorage implements IProxy { { method: method, headers: headers, - uri: uri, + uri: uri }, "making request: '@{method} @{uri}'" ); @@ -143,63 +152,65 @@ class ProxyStorage implements IProxy { headers['Content-Type'] = headers['Content-Type'] || HEADERS.JSON; } - const requestCallback = cb ? function(err, res, body): void { - let error; - const responseLength = err ? 0 : body.length; - // $FlowFixMe - processBody(); - logActivity(); - // $FlowFixMe - cb(err, res, body); + const requestCallback = cb + ? function (err, res, body): void { + let error; + const responseLength = err ? 0 : body.length; + // $FlowFixMe + processBody(); + logActivity(); + // $FlowFixMe + cb(err, res, body); - /** - * Perform a decode. - */ - function processBody(): void { - if (err) { - error = err.message; - return; - } + /** + * Perform a decode. + */ + function processBody(): void { + if (err) { + error = err.message; + return; + } - if (options.json && res.statusCode < 300) { - try { - // $FlowFixMe - body = JSON.parse(body.toString(CHARACTER_ENCODING.UTF8)); - } catch (_err) { - body = {}; - err = _err; - error = err.message; + if (options.json && res.statusCode < 300) { + try { + // $FlowFixMe + body = JSON.parse(body.toString(CHARACTER_ENCODING.UTF8)); + } catch (_err) { + body = {}; + err = _err; + error = err.message; + } + } + + if (!err && isObject(body)) { + if (_.isString(body.error)) { + error = body.error; + } + } + } + /** + * Perform a log. + */ + function logActivity(): void { + let message = "@{!status}, req: '@{request.method} @{request.url}'"; + message += error ? ', error: @{!error}' : ', bytes: @{bytes.in}/@{bytes.out}'; + self.logger.warn( + { + err: err || undefined, // if error is null/false change this to undefined so it wont log + request: { method: method, url: uri }, + level: 35, // http + status: res != null ? res.statusCode : 'ERR', + error: error, + bytes: { + in: json ? json.length : 0, + out: responseLength || 0 + } + }, + message + ); } } - - if (!err && isObject(body)) { - if (_.isString(body.error)) { - error = body.error; - } - } - } - /** - * Perform a log. - */ - function logActivity(): void { - let message = "@{!status}, req: '@{request.method} @{request.url}'"; - message += error ? ', error: @{!error}' : ', bytes: @{bytes.in}/@{bytes.out}'; - self.logger.warn( - { - err: err || undefined, // if error is null/false change this to undefined so it wont log - request: { method: method, url: uri }, - level: 35, // http - status: res != null ? res.statusCode : 'ERR', - error: error, - bytes: { - in: json ? json.length : 0, - out: responseLength || 0, - }, - }, - message - ); - } - } : undefined; + : undefined; let requestOptions = { url: uri, @@ -211,7 +222,7 @@ class ProxyStorage implements IProxy { gzip: true, timeout: this.timeout, strictSSL: this.strict_ssl, - agentOptions: this.agent_options, + agentOptions: this.agent_options }; if (this.ca) { @@ -223,7 +234,7 @@ class ProxyStorage implements IProxy { const req = request(requestOptions, requestCallback); let statusCalled = false; - req.on('response', function(res): void { + req.on('response', function (res): void { // FIXME: _verdaccio_aborted seems not used // @ts-ignore if (!req._verdaccio_aborted && !statusCalled) { @@ -238,17 +249,17 @@ class ProxyStorage implements IProxy { { request: { method: method, - url: uri, + url: uri }, level: 35, // http - status: _.isNull(res) === false ? res.statusCode : 'ERR', + status: _.isNull(res) === false ? res.statusCode : 'ERR' }, message ); })(); } }); - req.on('error', function(_err): void { + req.on('error', function (_err): void { // FIXME: _verdaccio_aborted seems not used // @ts-ignore if (!req._verdaccio_aborted && !statusCalled) { @@ -397,8 +408,11 @@ class ProxyStorage implements IProxy { public isUplinkValid(url: string): boolean { // $FlowFixMe const urlParsed: UrlWithStringQuery = URL.parse(url); - const isHTTPS = (urlDomainParsed: URL): boolean => urlDomainParsed.protocol === 'https:' && (urlParsed.port === null || urlParsed.port === '443'); - const getHost = (urlDomainParsed): boolean => (isHTTPS(urlDomainParsed) ? urlDomainParsed.hostname : urlDomainParsed.host); + const isHTTPS = (urlDomainParsed: URL): boolean => + urlDomainParsed.protocol === 'https:' && + (urlParsed.port === null || urlParsed.port === '443'); + const getHost = (urlDomainParsed): boolean => + isHTTPS(urlDomainParsed) ? urlDomainParsed.hostname : urlDomainParsed.host; const isMatchProtocol: boolean = urlParsed.protocol === this.url.protocol; const isMatchHost: boolean = getHost(urlParsed) === getHost(this.url); // @ts-ignore @@ -425,7 +439,7 @@ class ProxyStorage implements IProxy { uri: `/${encode(name)}`, json: true, headers: headers, - req: options.req, + req: options.req }, (err, res, body): void => { if (err) { @@ -435,7 +449,9 @@ class ProxyStorage implements IProxy { return callback(ErrorCode.getNotFound(API_ERROR.NOT_PACKAGE_UPLINK)); } if (!(res.statusCode >= HTTP_STATUS.OK && res.statusCode < HTTP_STATUS.MULTIPLE_CHOICES)) { - const error = ErrorCode.getInternalError(`${API_ERROR.BAD_STATUS_CODE}: ${res.statusCode}`); + const error = ErrorCode.getInternalError( + `${API_ERROR.BAD_STATUS_CODE}: ${res.statusCode}` + ); // $FlowFixMe error.remoteStatus = res.statusCode; return callback(error); @@ -460,16 +476,19 @@ class ProxyStorage implements IProxy { uri_full: url, encoding: null, headers: { - Accept: contentTypeAccept, - }, + Accept: contentTypeAccept + } }); - readStream.on('response', function(res: any) { + readStream.on('response', function (res: any) { if (res.statusCode === HTTP_STATUS.NOT_FOUND) { return stream.emit('error', ErrorCode.getNotFound(API_ERROR.NOT_FILE_UPLINK)); } if (!(res.statusCode >= HTTP_STATUS.OK && res.statusCode < HTTP_STATUS.MULTIPLE_CHOICES)) { - return stream.emit('error', ErrorCode.getInternalError(`bad uplink status code: ${res.statusCode}`)); + return stream.emit( + 'error', + ErrorCode.getInternalError(`bad uplink status code: ${res.statusCode}`) + ); } if (res.headers[HEADER_TYPE.CONTENT_LENGTH]) { expected_length = res.headers[HEADER_TYPE.CONTENT_LENGTH]; @@ -479,13 +498,13 @@ class ProxyStorage implements IProxy { readStream.pipe(stream); }); - readStream.on('error', function(err) { + readStream.on('error', function (err) { stream.emit('error', err); }); - readStream.on('data', function(data) { + readStream.on('data', function (data) { current_length += data.length; }); - readStream.on('end', function(data) { + readStream.on('end', function (data) { if (data) { current_length += data.length; } @@ -507,8 +526,8 @@ class ProxyStorage implements IProxy { uri: options.req.url, req: options.req, headers: { - referer: options.req.headers.referer, - }, + referer: options.req.headers.referer + } }); const parsePackage = (pkg: Package): void => { @@ -519,7 +538,10 @@ class ProxyStorage implements IProxy { requestStream.on('response', (res): void => { if (!String(res.statusCode).match(/^2\d\d$/)) { - return transformStream.emit('error', ErrorCode.getInternalError(`bad status code ${res.statusCode} from uplink`)); + return transformStream.emit( + 'error', + ErrorCode.getInternalError(`bad status code ${res.statusCode} from uplink`) + ); } // See https://github.com/request/request#requestoptions-callback @@ -568,7 +590,9 @@ class ProxyStorage implements IProxy { // FIXME: proxy logic is odd, something is wrong here. // @ts-ignore if (!this.proxy) { - headers['X-Forwarded-For'] = (req.headers['x-forwarded-for'] ? req.headers['x-forwarded-for'] + ', ' : '') + req.connection.remoteAddress; + headers['X-Forwarded-For'] = + (req.headers['x-forwarded-for'] ? req.headers['x-forwarded-for'] + ', ' : '') + + req.connection.remoteAddress; } } @@ -591,7 +615,7 @@ class ProxyStorage implements IProxy { if (this.failed_requests >= this.max_fails) { this.logger.warn( { - host: this.url.host, + host: this.url.host }, 'host @{host} is back online' ); @@ -602,7 +626,7 @@ class ProxyStorage implements IProxy { if (this.failed_requests === this.max_fails) { this.logger.warn( { - host: this.url.host, + host: this.url.host }, 'host @{host} is now offline' ); @@ -618,7 +642,10 @@ class ProxyStorage implements IProxy { * @private */ private _ifRequestFailure(): boolean { - return this.failed_requests >= this.max_fails && Math.abs(Date.now() - (this.last_request_time as number)) < this.fail_timeout; + return ( + this.failed_requests >= this.max_fails && + Math.abs(Date.now() - (this.last_request_time as number)) < this.fail_timeout + ); } /** @@ -628,7 +655,12 @@ class ProxyStorage implements IProxy { * @param {*} mainconfig * @param {*} isHTTPS */ - private _setupProxy(hostname: string, config: UpLinkConfLocal, mainconfig: Config, isHTTPS: boolean): void { + private _setupProxy( + hostname: string, + config: UpLinkConfLocal, + mainconfig: Config, + isHTTPS: boolean + ): void { let noProxyList; const proxy_key: string = isHTTPS ? 'https_proxy' : 'http_proxy'; @@ -658,10 +690,15 @@ class ProxyStorage implements IProxy { if (_.isArray(noProxyList)) { for (let i = 0; i < noProxyList.length; i++) { let noProxyItem = noProxyList[i]; - if (noProxyItem[0] !== '.') noProxyItem = '.' + noProxyItem; + if (noProxyItem[0] !== '.') { + noProxyItem = '.' + noProxyItem; + } if (hostname.lastIndexOf(noProxyItem) === hostname.length - noProxyItem.length) { if (this.proxy) { - this.logger.debug({ url: this.url.href, rule: noProxyItem }, 'not using proxy for @{url}, excluded by @{rule} rule'); + this.logger.debug( + { url: this.url.href, rule: noProxyItem }, + 'not using proxy for @{url}, excluded by @{rule} rule' + ); // @ts-ignore this.proxy = false; } @@ -674,7 +711,10 @@ class ProxyStorage implements IProxy { if (_.isString(this.proxy) === false) { delete this.proxy; } else { - this.logger.debug({ url: this.url.href, proxy: this.proxy }, 'using proxy @{proxy} for @{url}'); + this.logger.debug( + { url: this.url.href, proxy: this.proxy }, + 'using proxy @{proxy} for @{url}' + ); } } } diff --git a/src/lib/uplink-util.ts b/src/lib/uplink-util.ts index 9c50e1766..40edf88be 100644 --- a/src/lib/uplink-util.ts +++ b/src/lib/uplink-util.ts @@ -1,6 +1,6 @@ -import ProxyStorage from './up-storage'; import { Versions, Config } from '@verdaccio/types'; import { IProxy, ProxyList } from '../../types'; +import ProxyStorage from './up-storage'; /** * Set up the Up Storage for each link. diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 547c71f69..3de685f03 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,30 +1,17 @@ /** * @prettier */ -import _ from 'lodash'; import fs from 'fs'; import assert from 'assert'; +import URL from 'url'; +import { IncomingHttpHeaders } from 'http2'; +import _ from 'lodash'; import semver from 'semver'; import YAML from 'js-yaml'; -import URL from 'url'; import sanitizyReadme from '@verdaccio/readme'; -import { - APP_ERROR, - DEFAULT_PORT, - DEFAULT_DOMAIN, - DEFAULT_PROTOCOL, - CHARACTER_ENCODING, - HEADERS, - DIST_TAGS, - DEFAULT_USER, -} from './constants'; -import { generateGravatarUrl, GENERIC_AVATAR } from '../utils/user'; - import { Package, Version, Author } from '@verdaccio/types'; import { Request } from 'express'; -import { StringValue, AuthorAvatar } from '../../types'; -import { normalizeContributors } from './storage-utils'; import { getConflict, getBadData, @@ -34,9 +21,22 @@ import { getForbidden, getServiceUnavailable, getNotFound, - getCode, + getCode } from '@verdaccio/commons-api'; -import { IncomingHttpHeaders } from 'http2'; +import { generateGravatarUrl, GENERIC_AVATAR } from '../utils/user'; +import { StringValue, AuthorAvatar } from '../../types'; +import { + APP_ERROR, + DEFAULT_PORT, + DEFAULT_DOMAIN, + DEFAULT_PROTOCOL, + CHARACTER_ENCODING, + HEADERS, + DIST_TAGS, + DEFAULT_USER +} from './constants'; + +import { normalizeContributors } from './storage-utils'; import { logger } from './logger'; @@ -139,7 +139,11 @@ export function validateMetadata(object: Package, name: string): Package { * Create base url for registry. * @return {String} base registry url */ -export function combineBaseUrl(protocol: string, host: string | void, prefix?: string | void): string { +export function combineBaseUrl( + protocol: string, + host: string | void, + prefix?: string | void +): string { const result = `${protocol}://${host}`; const prefixOnlySlash = prefix === '/'; @@ -170,7 +174,11 @@ export function extractTarballFromUrl(url: string): string { * @param {*} config * @return {String} a filtered package */ -export function convertDistRemoteToLocalTarballUrls(pkg: Package, req: Request, urlPrefix: string | void): Package { +export function convertDistRemoteToLocalTarballUrls( + pkg: Package, + req: Request, + urlPrefix: string | void +): Package { for (const ver in pkg.versions) { if (Object.prototype.hasOwnProperty.call(pkg.versions, ver)) { const distName = pkg.versions[ver].dist; @@ -271,7 +279,7 @@ export function parseAddress(urlAddress: any): any { return { proto: urlPattern[2] || DEFAULT_PROTOCOL, host: urlPattern[6] || urlPattern[7] || DEFAULT_DOMAIN, - port: urlPattern[8] || DEFAULT_PORT, + port: urlPattern[8] || DEFAULT_PORT }; } @@ -280,7 +288,7 @@ export function parseAddress(urlAddress: any): any { if (urlPattern) { return { proto: urlPattern[2] || DEFAULT_PROTOCOL, - path: urlPattern[4], + path: urlPattern[4] }; } @@ -294,7 +302,7 @@ export function parseAddress(urlAddress: any): any { export function semverSort(listVersions: string[]): string[] { return ( listVersions - .filter(function(x): boolean { + .filter(function (x): boolean { if (!semver.parse(x, true)) { logger.warn({ ver: x }, 'ignoring bad version @{ver}'); return false; @@ -354,7 +362,7 @@ const parseIntervalTable = { d: 86400000, w: 7 * 86400000, M: 30 * 86400000, - y: 365 * 86400000, + y: 365 * 86400000 }; /** @@ -368,10 +376,16 @@ export function parseInterval(interval: any): number { } let result = 0; let last_suffix = Infinity; - interval.split(/\s+/).forEach(function(x): void { - if (!x) return; + interval.split(/\s+/).forEach(function (x): void { + if (!x) { + return; + } const m = x.match(/^((0|[1-9][0-9]*)(\.[0-9]+)?)(ms|s|m|h|d|w|M|y|)$/); - if (!m || parseIntervalTable[m[4]] >= last_suffix || (m[4] === '' && last_suffix !== Infinity)) { + if ( + !m || + parseIntervalTable[m[4]] >= last_suffix || + (m[4] === '' && last_suffix !== Infinity) + ) { throw Error('invalid interval: ' + interval); } last_suffix = parseIntervalTable[m[4]]; @@ -405,7 +419,7 @@ export const ErrorCode = { getForbidden, getServiceUnavailable, getNotFound, - getCode, + getCode }; export function parseConfigFile(configPath: string): any { @@ -452,7 +466,7 @@ export function fileExists(path: string): boolean { } export function sortByName(packages: any[], orderAscending: boolean | void = true): string[] { - return packages.slice().sort(function(a, b): number { + return packages.slice().sort(function (a, b): number { const comparatorNames = a.name.toLowerCase() < b.name.toLowerCase(); return orderAscending ? (comparatorNames ? -1 : 1) : comparatorNames ? 1 : -1; @@ -474,7 +488,9 @@ export function deleteProperties(propertiesToDelete: string[], objectItem: any): export function addGravatarSupport(pkgInfo: Package, online = true): AuthorAvatar { const pkgInfoCopy = { ...pkgInfo } as any; const author: any = _.get(pkgInfo, 'latest.author', null) as any; - const contributors: AuthorAvatar[] = normalizeContributors(_.get(pkgInfo, 'latest.contributors', [])); + const contributors: AuthorAvatar[] = normalizeContributors( + _.get(pkgInfo, 'latest.contributors', []) + ); const maintainers = _.get(pkgInfo, 'latest.maintainers', []); // for author. @@ -487,7 +503,7 @@ export function addGravatarSupport(pkgInfo: Package, online = true): AuthorAvata pkgInfoCopy.latest.author = { avatar: GENERIC_AVATAR, email: '', - author, + author }; } @@ -501,7 +517,7 @@ export function addGravatarSupport(pkgInfo: Package, online = true): AuthorAvata contributor = { avatar: GENERIC_AVATAR, email: contributor, - name: contributor, + name: contributor }; } @@ -564,7 +580,7 @@ export function formatAuthor(author: AuthorFormat): any { let authorDetails = { name: DEFAULT_USER, email: '', - url: '', + url: '' }; if (_.isNil(author)) { @@ -574,14 +590,14 @@ export function formatAuthor(author: AuthorFormat): any { if (_.isString(author)) { authorDetails = { ...authorDetails, - name: author as string, + name: author as string }; } if (_.isObject(author)) { authorDetails = { ...authorDetails, - ...(author as Author), + ...(author as Author) }; } diff --git a/src/utils/string.ts b/src/utils/string.ts index e9b0008d4..3f047fd4f 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -1,5 +1,7 @@ // @flow export function spliceURL(...args: string[]): string { - return Array.from(args).reduce((lastResult, current) => lastResult + current).replace(/([^:])(\/)+(.)/g, `$1/$3`); + return Array.from(args) + .reduce((lastResult, current) => lastResult + current) + .replace(/([^:])(\/)+(.)/g, `$1/$3`); } diff --git a/src/utils/user.ts b/src/utils/user.ts index 42b358ba9..c8cc6a768 100644 --- a/src/utils/user.ts +++ b/src/utils/user.ts @@ -1,27 +1,28 @@ // @flow -import {stringToMD5} from '../lib/crypto-utils'; import _ from 'lodash'; +import { stringToMD5 } from '../lib/crypto-utils'; // this is a generic avatar // https://www.iconfinder.com/icons/403017/anonym_avatar_default_head_person_unknown_user_icon // license: free commercial usage -export const GENERIC_AVATAR = 'data:image/svg+xml;utf8,' + -encodeURIComponent( -'' -); +export const GENERIC_AVATAR = + 'data:image/svg+xml;utf8,' + + encodeURIComponent( + '' + ); /** * Generate gravatar url from email address diff --git a/test/e2e-cli/setup/setup.ts b/test/e2e-cli/setup/setup.ts index 45d6e6820..7cbbe3256 100644 --- a/test/e2e-cli/setup/setup.ts +++ b/test/e2e-cli/setup/setup.ts @@ -1,30 +1,30 @@ -import fs from "fs"; -import path from "path"; -import os from "os"; -import {yellow} from "kleur"; -import {spawn} from "child_process"; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import { yellow } from 'kleur'; +import { spawn } from 'child_process'; import { npm } from '../utils/process'; import * as __global from '../utils/global.js'; module.exports = async () => { - const tempRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'verdaccio-cli-e2e-')); - __global.addItem('dir-root', tempRoot); - console.log(yellow(`Add temp root folder: ${tempRoot}`)); - fs.copyFileSync( - path.join(__dirname, '../config/_bootstrap_verdaccio.yaml'), - path.join(tempRoot, 'verdaccio.yaml'), - ); - // @ts-ignore - global.__namespace = __global; - console.log(`current directory: ${process.cwd()}`); - // @ts-ignore - global.registryProcess = spawn( - 'node', - [path.resolve('./bin/verdaccio'), '-c', './verdaccio.yaml'], - // @ts-ignore - { cwd: tempRoot, silence: false }, - ); + const tempRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'verdaccio-cli-e2e-')); + __global.addItem('dir-root', tempRoot); + console.log(yellow(`Add temp root folder: ${tempRoot}`)); + fs.copyFileSync( + path.join(__dirname, '../config/_bootstrap_verdaccio.yaml'), + path.join(tempRoot, 'verdaccio.yaml') + ); + // @ts-ignore + global.__namespace = __global; + console.log(`current directory: ${process.cwd()}`); + // @ts-ignore + global.registryProcess = spawn( + 'node', + [path.resolve('./bin/verdaccio'), '-c', './verdaccio.yaml'], + // @ts-ignore + { cwd: tempRoot, silence: false } + ); - // publish current build version on local registry - await npm('publish', '--registry' ,'http://localhost:4873'); -} + // publish current build version on local registry + await npm('publish', '--registry', 'http://localhost:4873'); +}; diff --git a/test/e2e-cli/setup/teardown.ts b/test/e2e-cli/setup/teardown.ts index 346c5c595..88e15cced 100644 --- a/test/e2e-cli/setup/teardown.ts +++ b/test/e2e-cli/setup/teardown.ts @@ -1,4 +1,4 @@ -module.exports = async function() { - // @ts-ignore - global.registryProcess.kill(); +module.exports = async function () { + // @ts-ignore + global.registryProcess.kill(); }; diff --git a/test/e2e-cli/setup/test_environment.ts b/test/e2e-cli/setup/test_environment.ts index 701a6ea76..ab47909a8 100644 --- a/test/e2e-cli/setup/test_environment.ts +++ b/test/e2e-cli/setup/test_environment.ts @@ -5,14 +5,15 @@ import NodeEnvironment from 'jest-environment-node'; const __global = require('../utils/global'); // import { npm } from '../utils/process'; - class E2ECliTestEnvironment extends NodeEnvironment { constructor(config) { - super(config) + super(config); } async setup() { - const tempRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'verdaccio-suite-test-')); + const tempRoot = fs.mkdtempSync( + path.join(fs.realpathSync(os.tmpdir()), 'verdaccio-suite-test-') + ); __global.addItem('dir-root', tempRoot); this.global.__namespace = __global; console.log(`current directory: ${process.cwd()}`); diff --git a/test/e2e-cli/test/__partials/npm_commands.ts b/test/e2e-cli/test/__partials/npm_commands.ts index 9f5515ce4..b821777d1 100644 --- a/test/e2e-cli/test/__partials/npm_commands.ts +++ b/test/e2e-cli/test/__partials/npm_commands.ts @@ -1,5 +1,13 @@ import { silentNpm } from '../../utils/process'; export function installVerdaccio(verdaccioInstall) { - return silentNpm('install', '--prefix', verdaccioInstall, 'verdaccio', '--registry' ,'http://localhost:4873', '--no-package-lock'); + return silentNpm( + 'install', + '--prefix', + verdaccioInstall, + 'verdaccio', + '--registry', + 'http://localhost:4873', + '--no-package-lock' + ); } diff --git a/test/e2e-cli/test/core/info.spec.ts b/test/e2e-cli/test/core/info.spec.ts index 5b956481f..deb91d9c9 100644 --- a/test/e2e-cli/test/core/info.spec.ts +++ b/test/e2e-cli/test/core/info.spec.ts @@ -1,27 +1,32 @@ import path from 'path'; -import {runVerdaccio} from '../../utils/process'; -import {installVerdaccio} from "../__partials/npm_commands"; +import { runVerdaccio } from '../../utils/process'; +import { installVerdaccio } from '../__partials/npm_commands'; -describe('verdaccio info', ()=> { - // @ts-ignore - const tempRootFolder = global.__namespace.getItem('dir-root'); - const verdaccioInstall = path.join(tempRootFolder, 'verdaccio-root-info'); - let registryProcess; +describe('verdaccio info', () => { + // @ts-ignore + const tempRootFolder = global.__namespace.getItem('dir-root'); + const verdaccioInstall = path.join(tempRootFolder, 'verdaccio-root-info'); + let registryProcess; - beforeAll(async () => { - await installVerdaccio(verdaccioInstall); - }, 30000); + beforeAll(async () => { + await installVerdaccio(verdaccioInstall); + }, 30000); - test('should run verdaccio info command', async () => { - const pathVerdaccioModule = require.resolve('verdaccio/bin/verdaccio', { - paths: [verdaccioInstall] - }); - const hasMatch = await runVerdaccio(pathVerdaccioModule, verdaccioInstall, ['--info'], /Environment/); + test('should run verdaccio info command', async () => { + const pathVerdaccioModule = require.resolve('verdaccio/bin/verdaccio', { + paths: [verdaccioInstall] + }); + const hasMatch = await runVerdaccio( + pathVerdaccioModule, + verdaccioInstall, + ['--info'], + /Environment/ + ); - expect(hasMatch.ok).toBeTruthy(); - }, 20000); + expect(hasMatch.ok).toBeTruthy(); + }, 20000); - afterAll(() => { - registryProcess.kill(); - }); + afterAll(() => { + registryProcess.kill(); + }); }); diff --git a/test/e2e-cli/test/core/listen.spec.ts b/test/e2e-cli/test/core/listen.spec.ts index df92f546a..986e37ea7 100644 --- a/test/e2e-cli/test/core/listen.spec.ts +++ b/test/e2e-cli/test/core/listen.spec.ts @@ -1,10 +1,10 @@ import path from 'path'; -import fs from "fs"; -import {installVerdaccio} from "../__partials/npm_commands"; -import {spawnRegistry} from "../../utils/registry"; -import {callRegistry} from "../../utils/web"; +import fs from 'fs'; +import { installVerdaccio } from '../__partials/npm_commands'; +import { spawnRegistry } from '../../utils/registry'; +import { callRegistry } from '../../utils/web'; -describe('npm install', ()=> { +describe('npm install', () => { jest.setTimeout(90000); const port = '9012'; @@ -24,10 +24,10 @@ describe('npm install', ()=> { paths: [verdaccioInstall] }); - registryProcess = await spawnRegistry(pathVerdaccioModule, - ['-c', configPath, '-l', port], - { cwd: verdaccioInstall, silent: true } - ); + registryProcess = await spawnRegistry(pathVerdaccioModule, ['-c', configPath, '-l', port], { + cwd: verdaccioInstall, + silent: true + }); const body = await callRegistry(`http://localhost:${port}/verdaccio`); const parsedBody = JSON.parse(body); diff --git a/test/e2e-cli/test/install/install.spec.ts b/test/e2e-cli/test/install/install.spec.ts index 72da34c68..8767d1d93 100644 --- a/test/e2e-cli/test/install/install.spec.ts +++ b/test/e2e-cli/test/install/install.spec.ts @@ -1,12 +1,12 @@ import path from 'path'; -import fs from "fs"; -import * as __global from "../../utils/global"; -import {spawnRegistry} from "../../utils/registry"; -import {execAndWaitForOutputToMatch} from '../../utils/process'; -import {installVerdaccio} from "../__partials/npm_commands"; -import {expectFileToExist} from "../../utils/expect"; +import fs from 'fs'; +import * as __global from '../../utils/global'; +import { spawnRegistry } from '../../utils/registry'; +import { execAndWaitForOutputToMatch } from '../../utils/process'; +import { installVerdaccio } from '../__partials/npm_commands'; +import { expectFileToExist } from '../../utils/expect'; -describe('npm install', ()=> { +describe('npm install', () => { jest.setTimeout(90000); const port = '9011'; @@ -25,26 +25,37 @@ describe('npm install', ()=> { const pathVerdaccioModule = require.resolve('verdaccio/bin/verdaccio', { paths: [verdaccioInstall] }); - registryProcess = await spawnRegistry(pathVerdaccioModule, - ['-c', configPath, '-l', port], - { cwd: verdaccioInstall, silent: true } - ); + registryProcess = await spawnRegistry(pathVerdaccioModule, ['-c', configPath, '-l', port], { + cwd: verdaccioInstall, + silent: true + }); }); test('should match on npm info verdaccio', async () => { // FIXME: not the best match, looking for a better way to match the terminal output - const output = await execAndWaitForOutputToMatch('npm', ['info', 'verdaccio', '--registry'], /A lightweight private npm proxy registry/); + const output = await execAndWaitForOutputToMatch( + 'npm', + ['info', 'verdaccio', '--registry'], + /A lightweight private npm proxy registry/ + ); expect(output.ok).toBeTruthy(); }); test('should install jquery', async () => { const testCwd = path.join(tempRootFolder, '_jquery_'); - await execAndWaitForOutputToMatch('npm', ['install', '--prefix', testCwd, 'jquery', '--registry' ,`http://localhost:${port}`], /''/, { - cwd: verdaccioInstall - }); + await execAndWaitForOutputToMatch( + 'npm', + ['install', '--prefix', testCwd, 'jquery', '--registry', `http://localhost:${port}`], + /''/, + { + cwd: verdaccioInstall + } + ); - const exist = await expectFileToExist(path.join(testCwd, 'node_modules', 'jquery', 'package.json')); + const exist = await expectFileToExist( + path.join(testCwd, 'node_modules', 'jquery', 'package.json') + ); expect(exist).toBeTruthy(); }); diff --git a/test/e2e-cli/utils/expect.ts b/test/e2e-cli/utils/expect.ts index e768caaba..306464960 100644 --- a/test/e2e-cli/utils/expect.ts +++ b/test/e2e-cli/utils/expect.ts @@ -1,13 +1,13 @@ import * as fs from 'fs-extra'; export function expectFileToExist(fileName: string) { - return new Promise((resolve, reject) => { - fs.exists(fileName, (exist) => { - if (exist) { - resolve(exist); - } else { - reject(new Error(`File ${fileName} was expected to exist but not found...`)); - } - }); - }); + return new Promise((resolve, reject) => { + fs.exists(fileName, (exist) => { + if (exist) { + resolve(exist); + } else { + reject(new Error(`File ${fileName} was expected to exist but not found...`)); + } + }); + }); } diff --git a/test/e2e-cli/utils/process.ts b/test/e2e-cli/utils/process.ts index 6b50fce94..c617ee19f 100644 --- a/test/e2e-cli/utils/process.ts +++ b/test/e2e-cli/utils/process.ts @@ -1,5 +1,5 @@ import * as child_process from 'child_process'; -import {SpawnOptions} from "child_process"; +import { SpawnOptions } from 'child_process'; export async function _exec(options, cmd, args) { let stdout = ''; @@ -7,12 +7,12 @@ export async function _exec(options, cmd, args) { const flags = []; const cwd = process.cwd(); const env = options.env; - console.log(`Running \`${cmd} ${args.map(x => `"${x}"`).join(' ')}\`${flags}...`); + console.log(`Running \`${cmd} ${args.map((x) => `"${x}"`).join(' ')}\`${flags}...`); console.log(`CWD: ${cwd}`); console.log(`ENV: ${JSON.stringify(env)}`); const spawnOptions = { cwd, - ...env ? { env } : {}, + ...(env ? { env } : {}) }; if (process.platform.startsWith('win')) { @@ -21,7 +21,6 @@ export async function _exec(options, cmd, args) { spawnOptions['stdio'] = 'pipe'; } - const childProcess = child_process.spawn(cmd, args, spawnOptions); childProcess.stdout.on('data', (data) => { stdout += data.toString('utf-8'); @@ -29,10 +28,11 @@ export async function _exec(options, cmd, args) { return; } - data.toString('utf-8') + data + .toString('utf-8') .split(/[\n\r]+/) - .filter(line => line !== '') - .forEach(line => console.log(' ' + line)); + .filter((line) => line !== '') + .forEach((line) => console.log(' ' + line)); }); childProcess.stderr.on('data', (data) => { @@ -41,10 +41,11 @@ export async function _exec(options, cmd, args) { return; } - data.toString('utf-8') + data + .toString('utf-8') .split(/[\n\r]+/) - .filter(line => line !== '') - .forEach(line => console.error((' ' + line))); + .filter((line) => line !== '') + .forEach((line) => console.error(' ' + line)); }); const err = new Error(`Running "${cmd} ${args.join(' ')}" returned error code `); @@ -63,7 +64,7 @@ export async function _exec(options, cmd, args) { childProcess.stdout.on('data', (data) => { // console.log("-->data==>", data.toString(), data.toString().match(match)); if (data.toString().match(match)) { - resolve({ok: true, stdout, stderr }); + resolve({ ok: true, stdout, stderr }); } }); childProcess.stderr.on('data', (data) => { @@ -76,14 +77,14 @@ export async function _exec(options, cmd, args) { } export function execAndWaitForOutputToMatch( - cmd: string, - args: string[], - match: RegExp, - spawnOptions: SpawnOptions = {}): any { + cmd: string, + args: string[], + match: RegExp, + spawnOptions: SpawnOptions = {} +): any { return _exec({ waitForMatch: match, ...spawnOptions, silence: true }, cmd, args); } - export function npm(...args) { return _exec({}, 'npm', args); } @@ -93,5 +94,5 @@ export function runVerdaccio(cmd, installation, args, match: RegExp): any { } export function silentNpm(...args) { - return _exec({silent: true}, 'npm', args); + return _exec({ silent: true }, 'npm', args); } diff --git a/test/e2e-cli/utils/registry.ts b/test/e2e-cli/utils/registry.ts index 6595ce546..dc4b1d39c 100644 --- a/test/e2e-cli/utils/registry.ts +++ b/test/e2e-cli/utils/registry.ts @@ -1,26 +1,21 @@ -import {fork} from "child_process"; +import { fork } from 'child_process'; -export function prepareEnvironment(rootFolder: string, folderName: string) { +export function prepareEnvironment(rootFolder: string, folderName: string) {} -} - -export function spawnRegistry( - verdaccioPath: string, - args: string[], - childOptions) { - return new Promise((resolve, reject) => { - let _childOptions = {silent: true, ...childOptions}; - - const childFork = fork(verdaccioPath, args, _childOptions); - - childFork.on('message', (msg) => { - if ('verdaccio_started' in msg) { - resolve(childFork); - } - }); - - childFork.on('error', (err) => reject([err])); - childFork.on('disconnect', (err) => reject([err])); - childFork.on('exit', (err) => reject([err])); - }); +export function spawnRegistry(verdaccioPath: string, args: string[], childOptions) { + return new Promise((resolve, reject) => { + let _childOptions = { silent: true, ...childOptions }; + + const childFork = fork(verdaccioPath, args, _childOptions); + + childFork.on('message', (msg) => { + if ('verdaccio_started' in msg) { + resolve(childFork); + } + }); + + childFork.on('error', (err) => reject([err])); + childFork.on('disconnect', (err) => reject([err])); + childFork.on('exit', (err) => reject([err])); + }); } diff --git a/test/e2e-cli/utils/utils.ts b/test/e2e-cli/utils/utils.ts index 6cc37b111..e648a3bba 100644 --- a/test/e2e-cli/utils/utils.ts +++ b/test/e2e-cli/utils/utils.ts @@ -1,9 +1,9 @@ -import path from "path"; -import fs from "fs"; +import path from 'path'; +import fs from 'fs'; export function copyConfigFile(rootFolder, configTemplate): string { - const configPath = path.join(rootFolder, 'verdaccio.yaml'); - fs.copyFileSync(path.join(__dirname, configTemplate), configPath); + const configPath = path.join(rootFolder, 'verdaccio.yaml'); + fs.copyFileSync(path.join(__dirname, configTemplate), configPath); - return configPath; + return configPath; } diff --git a/test/e2e-cli/utils/web.ts b/test/e2e-cli/utils/web.ts index e6d89f73a..3d300e5fe 100644 --- a/test/e2e-cli/utils/web.ts +++ b/test/e2e-cli/utils/web.ts @@ -1,23 +1,22 @@ -import {IncomingMessage} from 'http'; +import { IncomingMessage } from 'http'; import request from 'request'; - export function callRegistry(url: string): Promise { - return new Promise((resolve, reject) => { - let options = { - url: url, - headers: { 'Accept': 'application/json' }, - }; - // @ts-ignore - request(options, (error: any, response: IncomingMessage, body: string) => { - if (error) { - reject(error); - // @ts-ignore - } else if (response.statusCode >= 400) { - reject(new Error(`Requesting "${url}" returned status code ${response.statusCode}.`)); - } else { - resolve(body); - } - }); - }); + return new Promise((resolve, reject) => { + let options = { + url: url, + headers: { Accept: 'application/json' } + }; + // @ts-ignore + request(options, (error: any, response: IncomingMessage, body: string) => { + if (error) { + reject(error); + // @ts-ignore + } else if (response.statusCode >= 400) { + reject(new Error(`Requesting "${url}" returned status code ${response.statusCode}.`)); + } else { + resolve(body); + } + }); + }); } diff --git a/test/e2e/partials/pkg-protected.js b/test/e2e/partials/pkg-protected.js index 271f5e014..fb1d1b880 100644 --- a/test/e2e/partials/pkg-protected.js +++ b/test/e2e/partials/pkg-protected.js @@ -44,6 +44,7 @@ const json = { "_attachments": { "protected-pkg-5.0.5.tgz": { "content_type": "application\/octet-stream", + // eslint-disable-next-line max-len "data": "H4sIAAAAAAAAE+2W32vbMBDH85y\/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo\/\/79KPeQsnIw5KUDX\/9IOvurLuz\/DHSjK\/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1aW8eML+Vv10m9oF\/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0ScCdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI\/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yoEHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS\/pLQe+D+FIv\/agIWI6GX66kFuIhT+1gDjrp\/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0\/jWiAK8OcMjt8MW3OlfQppcuhhQ6k+2OgkK2Q8DssFPi\/IHpU9fz3\/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6\/f88f\/Pu47zomiPk2Lv\/dOv8h+P\/34\/D\/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=", "length": 512 } diff --git a/test/e2e/partials/pkg-scoped.js b/test/e2e/partials/pkg-scoped.js index 13da4e7bf..858cff451 100644 --- a/test/e2e/partials/pkg-scoped.js +++ b/test/e2e/partials/pkg-scoped.js @@ -44,6 +44,7 @@ const json = { "_attachments": { "@scope\/pk1-test-1.0.6.tgz": { "content_type": "application\/octet-stream", + // eslint-disable-next-line max-len "data": "H4sIAAAAAAAAE+2W32vbMBDH85y\/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo\/\/79KPeQsnIw5KUDX\/9IOvurLuz\/DHSjK\/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1aW8eML+Vv10m9oF\/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0ScCdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI\/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yoEHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS\/pLQe+D+FIv\/agIWI6GX66kFuIhT+1gDjrp\/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0\/jWiAK8OcMjt8MW3OlfQppcuhhQ6k+2OgkK2Q8DssFPi\/IHpU9fz3\/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6\/f88f\/Pu47zomiPk2Lv\/dOv8h+P\/34\/D\/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=", "length": 512 } diff --git a/test/functional/basic/basic.ts b/test/functional/basic/basic.ts index abd7782df..7fa413ebd 100644 --- a/test/functional/basic/basic.ts +++ b/test/functional/basic/basic.ts @@ -1,8 +1,14 @@ import fs from 'fs'; import path from 'path'; -import {createTarballHash} from "../../../src/lib/crypto-utils"; -import { HTTP_STATUS, DIST_TAGS} from "../../../src/lib/constants"; -import {CREDENTIALS, DOMAIN_SERVERS, PORT_SERVER_1, PORT_SERVER_2, TARBALL} from "../config.functional"; +import { createTarballHash } from '../../../src/lib/crypto-utils'; +import { HTTP_STATUS, DIST_TAGS } from '../../../src/lib/constants'; +import { + CREDENTIALS, + DOMAIN_SERVERS, + PORT_SERVER_1, + PORT_SERVER_2, + TARBALL +} from '../config.functional'; import whoIam from './whoIam'; import ping from './ping'; import fixturePkg from '../fixtures/package'; @@ -15,14 +21,14 @@ function getPackage(name) { return fixturePkg(name); } -export default function(server: any, server2: any) { +export default function (server: any, server2: any) { describe('basic test endpoints', () => { - const PKG_NAME = 'testpkg'; const PKG_VERSION = '0.0.1'; - beforeAll(function() { - return server.auth(CREDENTIALS.user, CREDENTIALS.password) + beforeAll(function () { + return server + .auth(CREDENTIALS.user, CREDENTIALS.password) .status(HTTP_STATUS.CREATED) .body_ok(/'test'/); }); @@ -31,7 +37,6 @@ export default function(server: any, server2: any) { ping(server); describe('handling packages', () => { - beforeAll(function () { return server.addPackage(PKG_NAME); }); @@ -40,29 +45,37 @@ export default function(server: any, server2: any) { return server.addPackage('testpkg-single-tarball'); }); - test('creating new package', () => {/* test for before() */ + test('creating new package', () => { + /* test for before() */ }); test('downloading non-existent tarball', () => { - return server.getTarball(PKG_NAME, TARBALL) + return server + .getTarball(PKG_NAME, TARBALL) .status(HTTP_STATUS.NOT_FOUND) .body_error(/no such file/); }); test('uploading incomplete tarball', () => { - return server.putTarballIncomplete(PKG_NAME, 'blahblah1', readfile('../fixtures/binary'), 3000); + return server.putTarballIncomplete( + PKG_NAME, + 'blahblah1', + readfile('../fixtures/binary'), + 3000 + ); }); describe('publishing package', () => { - beforeAll(function () { - return server.putTarball(PKG_NAME, TARBALL, readfile('../fixtures/binary')) + return server + .putTarball(PKG_NAME, TARBALL, readfile('../fixtures/binary')) .status(HTTP_STATUS.CREATED) .body_ok(/.*/); }); beforeAll(function () { - return server.putTarball('testpkg-single-tarball', 'single', readfile('../fixtures/binary')) + return server + .putTarball('testpkg-single-tarball', 'single', readfile('../fixtures/binary')) .status(HTTP_STATUS.CREATED) .body_ok(/.*/); }); @@ -90,13 +103,16 @@ export default function(server: any, server2: any) { // testexp-incomplete test('remove existing single tarball', () => { - return server.removeSingleTarball('testpkg-single-tarball', 'single').status(HTTP_STATUS.CREATED); + return server + .removeSingleTarball('testpkg-single-tarball', 'single') + .status(HTTP_STATUS.CREATED); }); // testexp-incomplete test('downloading newly created tarball', () => { - return server.getTarball(PKG_NAME, TARBALL) + return server + .getTarball(PKG_NAME, TARBALL) .status(200) .then(function (body) { expect(body).toEqual(readfile('../fixtures/binary')); @@ -107,36 +123,43 @@ export default function(server: any, server2: any) { let pkg = getPackage(PKG_NAME); pkg.dist.shasum = createTarballHash().update('fake').digest('hex'); - return server.putVersion(PKG_NAME, PKG_VERSION, pkg) + return server + .putVersion(PKG_NAME, PKG_VERSION, pkg) .status(HTTP_STATUS.BAD_REQUEST) .body_error(/shasum error/); }); describe('publishing version', () => { - beforeAll(function () { const pkg = getPackage(PKG_NAME); - pkg.dist.shasum = createTarballHash().update(readfile('../fixtures/binary')).digest('hex'); - return server.putVersion(PKG_NAME, PKG_VERSION, pkg) + pkg.dist.shasum = createTarballHash() + .update(readfile('../fixtures/binary')) + .digest('hex'); + return server + .putVersion(PKG_NAME, PKG_VERSION, pkg) .status(HTTP_STATUS.CREATED) .body_ok(/published/); }); describe('should download a package', () => { - beforeAll(function() { - return server.auth(CREDENTIALS.user, CREDENTIALS.password) + beforeAll(function () { + return server + .auth(CREDENTIALS.user, CREDENTIALS.password) .status(HTTP_STATUS.CREATED) .body_ok(new RegExp(CREDENTIALS.user)); }); test('should download a newly created package from server1', () => { - return server.getPackage(PKG_NAME) + return server + .getPackage(PKG_NAME) .status(HTTP_STATUS.OK) .then(function (body) { expect(body.name).toEqual(PKG_NAME); expect(body.versions[PKG_VERSION].name).toEqual(PKG_NAME); - expect(body.versions[PKG_VERSION].dist.tarball).toEqual(`http://${DOMAIN_SERVERS}:${PORT_SERVER_1}/${PKG_NAME}/-/${TARBALL}`); + expect(body.versions[PKG_VERSION].dist.tarball).toEqual( + `http://${DOMAIN_SERVERS}:${PORT_SERVER_1}/${PKG_NAME}/-/${TARBALL}` + ); expect(body[DIST_TAGS]).toEqual({ latest: PKG_VERSION }); @@ -144,51 +167,53 @@ export default function(server: any, server2: any) { }); test('should downloading a package from server2', () => { - return server2.getPackage(PKG_NAME) + return server2 + .getPackage(PKG_NAME) .status(HTTP_STATUS.OK) .then(function (body) { expect(body.name).toEqual(PKG_NAME); expect(body.versions[PKG_VERSION].name).toEqual(PKG_NAME); - expect(body.versions[PKG_VERSION].dist.tarball).toEqual(`http://${DOMAIN_SERVERS}:${PORT_SERVER_2}/${PKG_NAME}/-/${TARBALL}`); + expect(body.versions[PKG_VERSION].dist.tarball).toEqual( + `http://${DOMAIN_SERVERS}:${PORT_SERVER_2}/${PKG_NAME}/-/${TARBALL}` + ); expect(body[DIST_TAGS]).toEqual({ latest: PKG_VERSION }); }); }); - }); - }); }); }); describe('handle failures on endpoints', () => { - test('should fails trying to fetch non-existent package', () => { - return server.getPackage(PKG_NAME).status(HTTP_STATUS.NOT_FOUND).body_error(/no such package/); + return server + .getPackage(PKG_NAME) + .status(HTTP_STATUS.NOT_FOUND) + .body_error(/no such package/); }); - test( - 'should fails on publish a version for non existing package', - () => { - return server.putVersion('testpxg', PKG_VERSION, getPackage('testpxg')) - .status(HTTP_STATUS.NOT_FOUND) - .body_error(/no such package/); - } - ); + test('should fails on publish a version for non existing package', () => { + return server + .putVersion('testpxg', PKG_VERSION, getPackage('testpxg')) + .status(HTTP_STATUS.NOT_FOUND) + .body_error(/no such package/); + }); test('should be a package not found', () => { - return server.putTarball('nonExistingPackage', TARBALL, readfile('../fixtures/binary')) + return server + .putTarball('nonExistingPackage', TARBALL, readfile('../fixtures/binary')) .status(HTTP_STATUS.NOT_FOUND) .body_error(/no such/); }); test('should fails on publish package in a bad uplink', () => { - return server.putPackage('baduplink', getPackage('baduplink')) + return server + .putPackage('baduplink', getPackage('baduplink')) .status(HTTP_STATUS.SERVICE_UNAVAILABLE) .body_error(/one of the uplinks is down, refuse to publish/); }); - }); }); } diff --git a/test/functional/basic/ping.ts b/test/functional/basic/ping.ts index ceea25433..02a0ae2d1 100644 --- a/test/functional/basic/ping.ts +++ b/test/functional/basic/ping.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -export default function(server) { +export default function (server) { test('ping', () => { return server.ping().then(function (data) { // it's always an empty object diff --git a/test/functional/basic/whoIam.ts b/test/functional/basic/whoIam.ts index 19eed1023..aafd82a95 100644 --- a/test/functional/basic/whoIam.ts +++ b/test/functional/basic/whoIam.ts @@ -1,7 +1,6 @@ -import {CREDENTIALS} from "../config.functional"; - -export default function(server) { +import { CREDENTIALS } from '../config.functional'; +export default function (server) { test('who am I?', () => { return server.whoami().then(function (username) { expect(username).toMatch(CREDENTIALS.user); diff --git a/test/functional/fixtures/package.ts b/test/functional/fixtures/package.ts index b3ad9672e..11abd027d 100644 --- a/test/functional/fixtures/package.ts +++ b/test/functional/fixtures/package.ts @@ -1,14 +1,20 @@ -import {DOMAIN_SERVERS, PORT_SERVER_1, TARBALL} from '../config.functional'; +import { DOMAIN_SERVERS, PORT_SERVER_1, TARBALL } from '../config.functional'; -export default function(name, version = '0.0.0', port = PORT_SERVER_1, domain= `http://${DOMAIN_SERVERS}:${port}`, - fileName = TARBALL, readme = 'this is a readme'): any { +export default function ( + name, + version = '0.0.0', + port = PORT_SERVER_1, + domain = `http://${DOMAIN_SERVERS}:${port}`, + fileName = TARBALL, + readme = 'this is a readme' +): any { return { name, version, readme, dist: { shasum: 'fake', - tarball: `${domain}/${encodeURIComponent(name)}/-/${fileName}`, - }, + tarball: `${domain}/${encodeURIComponent(name)}/-/${fileName}` + } }; } diff --git a/test/functional/index.spec.ts b/test/functional/index.spec.ts index 482b222b9..f1c0d8e8c 100644 --- a/test/functional/index.spec.ts +++ b/test/functional/index.spec.ts @@ -3,7 +3,7 @@ import { setup } from '../../src/lib/logger'; setup([]); -import {IServerBridge} from '../types'; +import { IServerBridge } from '../types'; import basic from './basic/basic'; import packageAccess from './package/access'; @@ -29,7 +29,7 @@ import middleware from './plugins/middleware'; import upLinkCache from './uplinks/cache'; import uplinkTimeout from './uplinks/timeout'; -describe('functional test verdaccio', function() { +describe('functional test verdaccio', function () { jest.setTimeout(20000); // @ts-ignore const server1: IServerBridge = global.__SERVERS__[0]; @@ -65,13 +65,12 @@ describe('functional test verdaccio', function() { adduser(server1); logout(server1); basic(server1, server2); - simpleSearch(server1, server2, app) - + simpleSearch(server1, server2, app); }); -process.on('unhandledRejection', function(err) { - console.error("unhandledRejection", err); - process.nextTick(function() { +process.on('unhandledRejection', function (err) { + console.error('unhandledRejection', err); + process.nextTick(function () { throw err; }); }); diff --git a/test/functional/lib/environment.ts b/test/functional/lib/environment.ts index f347f997a..b1ad51a9f 100644 --- a/test/functional/lib/environment.ts +++ b/test/functional/lib/environment.ts @@ -1,12 +1,12 @@ import { yellow, green, blue, magenta } from 'kleur'; import path from 'path'; import NodeEnvironment from 'jest-environment-node'; -import {VerdaccioConfig} from '../../lib/verdaccio-server'; +import { VerdaccioConfig } from '../../lib/verdaccio-server'; import VerdaccioProcess from '../../lib/server_process'; import Server from '../../lib/server'; import ExpressServer from './simple_server'; -import {IServerBridge} from '../../types'; -import {DOMAIN_SERVERS, PORT_SERVER_1, PORT_SERVER_2, PORT_SERVER_3} from '../config.functional'; +import { IServerBridge } from '../../types'; +import { DOMAIN_SERVERS, PORT_SERVER_1, PORT_SERVER_2, PORT_SERVER_3 } from '../config.functional'; const EXPRESS_PORT = 55550; @@ -14,7 +14,7 @@ class FunctionalEnvironment extends NodeEnvironment { public config: any; public constructor(config: any) { - super(config) + super(config); } public async startWeb() { @@ -23,11 +23,12 @@ class FunctionalEnvironment extends NodeEnvironment { return await express.start(EXPRESS_PORT); } - public async setup() { const SILENCE_LOG = !process.env.VERDACCIO_DEBUG; // @ts-ignore - const DEBUG_INJECT: boolean = process.env.VERDACCIO_DEBUG_INJECT ? process.env.VERDACCIO_DEBUG_INJECT : false; + const DEBUG_INJECT: boolean = process.env.VERDACCIO_DEBUG_INJECT + ? process.env.VERDACCIO_DEBUG_INJECT + : false; const forkList: any[] = []; const serverList: IServerBridge[] = []; const pathStore = path.join(__dirname, '../store'); @@ -58,7 +59,9 @@ class FunctionalEnvironment extends NodeEnvironment { const verdaccioConfig = new VerdaccioConfig( path.join(pathStore, config.storage), path.join(pathStore, config.config), - `http://${DOMAIN_SERVERS}:${config.port}/`, config.port); + `http://${DOMAIN_SERVERS}:${config.port}/`, + config.port + ); console.log(magenta(`Running registry ${config.config} on port ${config.port}`)); const server: IServerBridge = new Server(verdaccioConfig.domainPath); serverList.push(server); @@ -80,7 +83,7 @@ class FunctionalEnvironment extends NodeEnvironment { console.log(yellow('Teardown Test Environment.')); // @ts-ignore if (!this.global.__SERVERS_PROCESS__) { - throw new Error("There are no servers to stop"); + throw new Error('There are no servers to stop'); } // shutdown verdaccio @@ -95,7 +98,7 @@ class FunctionalEnvironment extends NodeEnvironment { // @ts-ignore public runScript(script: string) { - // @ts-ignore + // @ts-ignore return super.runScript(script); } } diff --git a/test/functional/lib/setup.ts b/test/functional/lib/setup.ts index 79ba46831..f43cd9870 100644 --- a/test/functional/lib/setup.ts +++ b/test/functional/lib/setup.ts @@ -1,3 +1,3 @@ -module.exports = async function() { +module.exports = async function () { // here we should create dynamically config files }; diff --git a/test/functional/lib/simple_server.ts b/test/functional/lib/simple_server.ts index 82edb9566..3a9e13337 100644 --- a/test/functional/lib/simple_server.ts +++ b/test/functional/lib/simple_server.ts @@ -26,9 +26,11 @@ export default class ExpressServer { public start(port: number): Promise { return new Promise((resolve) => { this.app.use(bodyParser.json()); - this.app.use(bodyParser.urlencoded({ - extended: true - })); + this.app.use( + bodyParser.urlencoded({ + extended: true + }) + ); this.server = this.app.listen(port, () => resolve(this)); }); diff --git a/test/functional/lib/test.utils.ts b/test/functional/lib/test.utils.ts index 2a8286af8..a0ca772c4 100644 --- a/test/functional/lib/test.utils.ts +++ b/test/functional/lib/test.utils.ts @@ -1,14 +1,20 @@ -import crypto from 'crypto'; +import crypto from 'crypto'; import fs from 'fs'; import path from 'path'; function generateSha(key) { // @ts-ignore - return crypto.createHash('sha1', 'binary').update(key).digest('hex'); + return ( + crypto + // @ts-ignore + .createHash('sha1', 'binary') + .update(key) + .digest('hex') + ); } function readFile(filePath) { return fs.readFileSync(path.join(__dirname, `/${filePath}`)); } -export { generateSha, readFile } +export { generateSha, readFile }; diff --git a/test/functional/notifications/notify.ts b/test/functional/notifications/notify.ts index 10e3ecb4b..6f1642d86 100644 --- a/test/functional/notifications/notify.ts +++ b/test/functional/notifications/notify.ts @@ -1,30 +1,32 @@ import _ from 'lodash'; -import {HEADERS} from '../../../src/lib/constants'; -import {notify} from '../../../src/lib/notify'; -import {DOMAIN_SERVERS, PORT_SERVER_APP} from '../config.functional'; +import { HEADERS } from '../../../src/lib/constants'; +import { notify } from '../../../src/lib/notify'; +import { DOMAIN_SERVERS, PORT_SERVER_APP } from '../config.functional'; import { RemoteUser } from '@verdaccio/types'; -export default function(express) { +export default function (express) { const config = { notify: { method: 'POST', - headers: [{ - 'Content-Type': HEADERS.JSON - }], + headers: [ + { + 'Content-Type': HEADERS.JSON + } + ], endpoint: `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/api/notify`, + // eslint-disable-next-line max-len content: `{"color":"green","message":"New package published: * {{ name }}*. Publisher name: * {{ publisher.name }} *.","notify":true,"message_format":"text"}` } }; const publisherInfo: RemoteUser = { - name: "publisher-name-test", + name: 'publisher-name-test', real_groups: [], groups: [] }; describe('notifications', () => { - function parseBody(notification) { const jsonBody = JSON.parse(notification); @@ -41,26 +43,30 @@ export default function(express) { }); }); - test('notification should be send', done => { + test('notification should be send', (done) => { const metadata = { - name: "pkg-test" + name: 'pkg-test' }; // @ts-ignore - notify(metadata, config, publisherInfo, 'foo').then(function (body) { - const jsonBody = parseBody(body); - expect( - `New package published: * ${metadata.name}*. Publisher name: * ${publisherInfo.name} *.`).toBe(jsonBody.message); - done(); - }, function (err) { - expect(err).toBeDefined(); - done(); - }); + notify(metadata, config, publisherInfo, 'foo').then( + function (body) { + const jsonBody = parseBody(body); + expect( + `New package published: * ${metadata.name}*. Publisher name: * ${publisherInfo.name} *.` + ).toBe(jsonBody.message); + done(); + }, + function (err) { + expect(err).toBeDefined(); + done(); + } + ); }); - test('notification should be send single header', done => { + test('notification should be send single header', (done) => { const metadata = { - name: "pkg-test" + name: 'pkg-test' }; const configMultipleHeader = _.cloneDeep(config); @@ -70,68 +76,81 @@ export default function(express) { }; // @ts-ignore - notify(metadata, configMultipleHeader, publisherInfo).then(function (body) { - const jsonBody = parseBody(body); - expect(`New package published: * ${metadata.name}*. Publisher name: * ${publisherInfo.name} *.`).toBe(jsonBody.message); - done(); - }, function (err) { - expect(err).toBeDefined(); - done(); - }); - }); - - test('notification should be send multiple notifications endpoints', done => { - const metadata = { - name: "pkg-test" - }; - // let notificationsCounter = 0; - - const multipleNotificationsEndpoint = { - notify: [] - }; - - for (let i = 0; i < 10; i++) { - const notificationSettings = _.cloneDeep(config.notify); - // basically we allow al notifications - // @ts-ignore - notificationSettings.packagePattern = /^pkg-test$/; - // notificationSettings.packagePatternFlags = 'i'; - // @ts-ignore - multipleNotificationsEndpoint.notify.push(notificationSettings); - } - - // @ts-ignore - notify(metadata, multipleNotificationsEndpoint, publisherInfo).then(function (body) { - console.log("--->body", body); - body.forEach(function(notification) { - const jsonBody = parseBody(notification); - expect(`New package published: * ${metadata.name}*. Publisher name: * ${publisherInfo.name} *.`).toBe(jsonBody.message); - }); + notify(metadata, configMultipleHeader, publisherInfo).then( + function (body) { + const jsonBody = parseBody(body); + expect( + `New package published: * ${metadata.name}*. Publisher name: * ${publisherInfo.name} *.` + ).toBe(jsonBody.message); done(); - }, function (err) { + }, + function (err) { expect(err).toBeDefined(); done(); - }); - }); + } + ); + }); - test('notification should fails', done => { + test('notification should be send multiple notifications endpoints', (done) => { const metadata = { - name: "pkg-test" + name: 'pkg-test' + }; + // let notificationsCounter = 0; + + const multipleNotificationsEndpoint = { + notify: [] + }; + + for (let i = 0; i < 10; i++) { + const notificationSettings = _.cloneDeep(config.notify); + // basically we allow al notifications + // @ts-ignore + notificationSettings.packagePattern = /^pkg-test$/; + // notificationSettings.packagePatternFlags = 'i'; + // @ts-ignore + multipleNotificationsEndpoint.notify.push(notificationSettings); + } + + // @ts-ignore + notify(metadata, multipleNotificationsEndpoint, publisherInfo).then( + function (body) { + console.log('--->body', body); + body.forEach(function (notification) { + const jsonBody = parseBody(notification); + expect( + `New package published: * ${metadata.name}*. Publisher name: * ${publisherInfo.name} *.` + ).toBe(jsonBody.message); + }); + done(); + }, + function (err) { + expect(err).toBeDefined(); + done(); + } + ); + }); + + test('notification should fails', (done) => { + const metadata = { + name: 'pkg-test' }; const configFail = _.cloneDeep(config); configFail.notify.endpoint = `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/api/notify/bad`; // @ts-ignore - notify(metadata, configFail, publisherInfo).then(function () { - expect(false).toBe('This service should fails with status code 400'); - done(); - }, function (err) { - expect(err).toEqual('bad response'); - done(); - }); + notify(metadata, configFail, publisherInfo).then( + function () { + expect(false).toBe('This service should fails with status code 400'); + done(); + }, + function (err) { + expect(err).toEqual('bad response'); + done(); + } + ); }); - test('publisher property should not be overridden if it exists in metadata', done => { + test('publisher property should not be overridden if it exists in metadata', (done) => { const metadata = { name: 'pkg-test', publisher: { @@ -141,17 +160,18 @@ export default function(express) { // @ts-ignore notify(metadata, config, publisherInfo).then( - function(body) { + function (body) { const jsonBody = parseBody(body); - expect(`New package published: * ${metadata.name}*. Publisher name: * ${metadata.publisher.name} *.`).toBe(jsonBody.message); + expect( + `New package published: * ${metadata.name}*. Publisher name: * ${metadata.publisher.name} *.` + ).toBe(jsonBody.message); done(); }, - function(err) { + function (err) { expect(err).toBeDefined(); done(); } ); }); - }); } diff --git a/test/functional/package/access.ts b/test/functional/package/access.ts index 0659f10c9..16a822751 100644 --- a/test/functional/package/access.ts +++ b/test/functional/package/access.ts @@ -1,13 +1,12 @@ -import {buildToken} from "../../../src/lib/utils"; -import {API_ERROR, HTTP_STATUS, TOKEN_BASIC} from "../../../src/lib/constants"; -import {CREDENTIALS} from "../config.functional"; +import { buildToken } from '../../../src/lib/utils'; +import { API_ERROR, HTTP_STATUS, TOKEN_BASIC } from '../../../src/lib/constants'; +import { CREDENTIALS } from '../config.functional'; import fixturePkg from '../fixtures/package'; -export default function(server) { - +export default function (server) { describe('package access control', () => { const buildAccesToken = (auth) => { - return buildToken(TOKEN_BASIC, `${(Buffer.from(auth).toString('base64'))}`); + return buildToken(TOKEN_BASIC, `${Buffer.from(auth).toString('base64')}`); }; /** @@ -17,18 +16,16 @@ export default function(server) { * @param status {boolean} */ function checkAccess(auth, pkg, status) { - test( - `${(status ? 'allows' : 'forbids')} access ${auth} to ${pkg}`, () => { - server.authstr = auth ? buildAccesToken(auth) : undefined; - const req = server.getPackage(pkg); + test(`${status ? 'allows' : 'forbids'} access ${auth} to ${pkg}`, () => { + server.authstr = auth ? buildAccesToken(auth) : undefined; + const req = server.getPackage(pkg); - if (status === HTTP_STATUS.NOT_FOUND) { - return req.status(HTTP_STATUS.NOT_FOUND).body_error(API_ERROR.NO_PACKAGE); - } else if (status === HTTP_STATUS.FORBIDDEN) { - return req.status(HTTP_STATUS.FORBIDDEN).body_error(API_ERROR.NOT_ALLOWED); - } + if (status === HTTP_STATUS.NOT_FOUND) { + return req.status(HTTP_STATUS.NOT_FOUND).body_error(API_ERROR.NO_PACKAGE); + } else if (status === HTTP_STATUS.FORBIDDEN) { + return req.status(HTTP_STATUS.FORBIDDEN).body_error(API_ERROR.NOT_ALLOWED); } - ); + }); } /** @@ -38,7 +35,7 @@ export default function(server) { * @param status {boolean} */ function checkPublish(auth, pkg, status) { - test(`${(status ? 'allows' : 'forbids')} publish ${auth} to ${pkg}`, () => { + test(`${status ? 'allows' : 'forbids'} publish ${auth} to ${pkg}`, () => { server.authstr = auth ? buildAccesToken(auth) : undefined; const req = server.putPackage(pkg, fixturePkg(pkg)); if (status === HTTP_STATUS.NOT_FOUND) { diff --git a/test/functional/package/gzip.ts b/test/functional/package/gzip.ts index e53635ee8..7da2edc5c 100644 --- a/test/functional/package/gzip.ts +++ b/test/functional/package/gzip.ts @@ -1,21 +1,23 @@ +/* eslint-disable jest/no-standalone-expect */ import zlib from 'zlib'; -import {readFile} from '../lib/test.utils'; -import {HEADER_TYPE, HEADERS, HTTP_STATUS, CHARACTER_ENCODING} from "../../../src/lib/constants"; +import { readFile } from '../lib/test.utils'; +import { HEADER_TYPE, HEADERS, HTTP_STATUS, CHARACTER_ENCODING } from '../../../src/lib/constants'; -export default function(server, express) { +export default function (server, express) { const PKG_NAME = 'testexp_gzip'; const PKG_VERSION = '0.0.1'; const PKG_BAD_DATA = 'testexp_baddata'; const VERSION_TOTAL = 4; - describe('test gzip support', () => { - beforeAll(function() { - express.get(`/${PKG_NAME}`, function(req, res) { - const pkg = JSON.parse(readFile('../fixtures/publish.json5') - .toString(CHARACTER_ENCODING.UTF8) - .replace(/__NAME__/g, PKG_NAME) - .replace(/__VERSION__/g, PKG_VERSION)); + beforeAll(function () { + express.get(`/${PKG_NAME}`, function (req, res) { + const pkg = JSON.parse( + readFile('../fixtures/publish.json5') + .toString(CHARACTER_ENCODING.UTF8) + .replace(/__NAME__/g, PKG_NAME) + .replace(/__VERSION__/g, PKG_VERSION) + ); // overcoming compress threshold for (let i = 1; i <= VERSION_TOTAL; i++) { @@ -30,7 +32,7 @@ export default function(server, express) { }); }); - express.get(`/${PKG_BAD_DATA}`, function(req, res) { + express.get(`/${PKG_BAD_DATA}`, function (req, res) { expect(req).toBeDefined(); expect(res).toBeDefined(); expect(req.headers[HEADER_TYPE.ACCEPT_ENCODING]).toBe(HEADERS.GZIP); @@ -44,37 +46,41 @@ export default function(server, express) { }); test('should understand non gzipped data from uplink', () => { - return server.getPackage(PKG_NAME) + return server + .getPackage(PKG_NAME) .status(HTTP_STATUS.OK) .response((res) => { expect(res.headers[HEADER_TYPE.CONTENT_ENCODING]).toBeUndefined(); - }).then(body => { + }) + .then((body) => { expect(body.name).toBe(PKG_NAME); expect(Object.keys(body.versions)).toHaveLength(VERSION_TOTAL); }); }); test('should serve gzipped data', () => { - return server.request({ - uri: `/${PKG_NAME}`, - encoding: null, - headers: { - [HEADER_TYPE.ACCEPT_ENCODING]: HEADERS.GZIP, - }, - json: false, - }).status(HTTP_STATUS.OK) - .response(function(res) { + return server + .request({ + uri: `/${PKG_NAME}`, + encoding: null, + headers: { + [HEADER_TYPE.ACCEPT_ENCODING]: HEADERS.GZIP + }, + json: false + }) + .status(HTTP_STATUS.OK) + .response(function (res) { expect(res.headers[HEADER_TYPE.CONTENT_ENCODING]).toBe(HEADERS.GZIP); }) - .then(async function(body) { + .then(async function (body) { // should fails since is zipped - expect(function() { + expect(function () { JSON.parse(body.toString(CHARACTER_ENCODING.UTF8)); }).toThrow(/Unexpected/); // we unzip content and check content - await new Promise(function(resolve) { - zlib.gunzip(body, function(err, buffer) { + await new Promise(function (resolve) { + zlib.gunzip(body, function (err, buffer) { expect(err).toBeNull(); expect(buffer).not.toBeNull(); const unzipedBody = JSON.parse(buffer.toString()); diff --git a/test/functional/package/scoped.ts b/test/functional/package/scoped.ts index c5133def7..12605d965 100644 --- a/test/functional/package/scoped.ts +++ b/test/functional/package/scoped.ts @@ -1,32 +1,35 @@ -import {HEADERS, HTTP_STATUS} from '../../../src/lib/constants'; -import {DOMAIN_SERVERS, PORT_SERVER_1, PORT_SERVER_2} from '../config.functional'; -import {generateSha} from '../lib/test.utils'; -import {DIST_TAGS} from "../../../src/lib/constants"; +import { HEADERS, HTTP_STATUS } from '../../../src/lib/constants'; +import { DOMAIN_SERVERS, PORT_SERVER_1, PORT_SERVER_2 } from '../config.functional'; +import { generateSha } from '../lib/test.utils'; +import { DIST_TAGS } from '../../../src/lib/constants'; -export default function(server, server2) { +export default function (server, server2) { const SCOPE = '@test/scoped'; const PKG_VERSION = '1.0.0'; const PKG_NAME = 'scoped'; describe('test-scoped', () => { - beforeAll(function() { - return server.request({ - uri: '/@test%2fscoped', - headers: { - 'content-type': HEADERS.JSON, - }, - method: 'PUT', - json: require('./scoped.json'), - }).status(HTTP_STATUS.CREATED); + beforeAll(function () { + return server + .request({ + uri: '/@test%2fscoped', + headers: { + 'content-type': HEADERS.JSON + }, + method: 'PUT', + json: require('./scoped.json') + }) + .status(HTTP_STATUS.CREATED); }); test('should publish scope package', () => {}); describe('should get scoped packages tarball', () => { const uploadScopedTarBall = (server) => { - return server.getTarball(SCOPE, `${PKG_NAME}-${PKG_VERSION}.tgz`) + return server + .getTarball(SCOPE, `${PKG_NAME}-${PKG_VERSION}.tgz`) .status(HTTP_STATUS.OK) - .then(function(body) { + .then(function (body) { // not real sha due to utf8 conversion expect(generateSha(body)).toEqual('6e67b14e2c0e450b942e2bc8086b49e90f594790'); }); @@ -39,19 +42,21 @@ export default function(server, server2) { test('should be a scoped tarball from server2', () => { return uploadScopedTarBall(server2); }); - }); describe('should retrieve scoped packages', () => { - const testScopePackage = (server, port) => server.getPackage(SCOPE) - .status(HTTP_STATUS.OK) - .then(function(body) { - expect(body.name).toBe(SCOPE); - expect(body.versions[PKG_VERSION].name).toBe(SCOPE); - expect(body.versions[PKG_VERSION].dist.tarball).toBe( - `http://${DOMAIN_SERVERS}:${port}/@test%2fscoped/-/${PKG_NAME}-${PKG_VERSION}.tgz`); - expect(body[DIST_TAGS]).toEqual({latest: PKG_VERSION}); - }); + const testScopePackage = (server, port) => + server + .getPackage(SCOPE) + .status(HTTP_STATUS.OK) + .then(function (body) { + expect(body.name).toBe(SCOPE); + expect(body.versions[PKG_VERSION].name).toBe(SCOPE); + expect(body.versions[PKG_VERSION].dist.tarball).toBe( + `http://${DOMAIN_SERVERS}:${port}/@test%2fscoped/-/${PKG_NAME}-${PKG_VERSION}.tgz` + ); + expect(body[DIST_TAGS]).toEqual({ latest: PKG_VERSION }); + }); test('scoped package on server1', () => testScopePackage(server, PORT_SERVER_1)); test('scoped package on server2', () => testScopePackage(server2, PORT_SERVER_2)); @@ -59,13 +64,16 @@ export default function(server, server2) { describe('should retrieve a scoped packages under nginx', () => { test('should work nginx workaround', () => { - return server2.request({ - uri: '/@test/scoped/1.0.0' - }).status(HTTP_STATUS.OK) - .then(function(body) { + return server2 + .request({ + uri: '/@test/scoped/1.0.0' + }) + .status(HTTP_STATUS.OK) + .then(function (body) { expect(body.name).toEqual(SCOPE); expect(body.dist.tarball).toEqual( - `http://${DOMAIN_SERVERS}:${PORT_SERVER_2}/@test%2fscoped/-/${PKG_NAME}-${PKG_VERSION}.tgz`); + `http://${DOMAIN_SERVERS}:${PORT_SERVER_2}/@test%2fscoped/-/${PKG_NAME}-${PKG_VERSION}.tgz` + ); }); }); }); diff --git a/test/functional/performance/race.ts b/test/functional/performance/race.ts index fed905e4a..23354d465 100644 --- a/test/functional/performance/race.ts +++ b/test/functional/performance/race.ts @@ -1,11 +1,10 @@ import async from 'async'; -import { HTTP_STATUS } from "../../../src/lib/constants"; +import { HTTP_STATUS } from '../../../src/lib/constants'; let okTotalSum = 0; -import racePkg from '../fixtures/package'; - -export default function(server) { +import racePkg from '../fixtures/package'; +export default function (server) { describe('should test race condition on publish packages', () => { const MAX_COUNT = 20; const PKG_NAME = 'race'; @@ -14,14 +13,15 @@ export default function(server) { const UNAVAILABLE = 'unavailable'; beforeAll(function () { - return server.putPackage(PKG_NAME, racePkg(PKG_NAME)) + return server + .putPackage(PKG_NAME, racePkg(PKG_NAME)) .status(HTTP_STATUS.CREATED) .body_ok(/created new package/); }); test('creating new package', () => {}); - test('should uploading 10 same versions and ignore 9', callback => { + test('should uploading 10 same versions and ignore 9', (callback) => { let listOfRequest = []; for (let i = 0; i < MAX_COUNT; i++) { // @ts-ignore @@ -30,11 +30,14 @@ export default function(server) { data.rand = Math.random(); let _res; - server.putVersion(PKG_NAME, '0.0.1', data).response(function (res) { - _res = res; - }).then(function (body) { - callback(null, [_res, body]); - }); + server + .putVersion(PKG_NAME, '0.0.1', data) + .response(function (res) { + _res = res; + }) + .then(function (body) { + callback(null, [_res, body]); + }); }); } @@ -57,7 +60,10 @@ export default function(server) { failCount++; } - if (resp.statusCode === HTTP_STATUS.SERVICE_UNAVAILABLE && ~body.error.indexOf(UNAVAILABLE)) { + if ( + resp.statusCode === HTTP_STATUS.SERVICE_UNAVAILABLE && + ~body.error.indexOf(UNAVAILABLE) + ) { failCount++; } }); @@ -71,14 +77,15 @@ export default function(server) { }); }); - test('shoul uploading 10 diff versions and accept 10', callback => { + test('shoul uploading 10 diff versions and accept 10', (callback) => { const listofRequest = []; for (let i = 0; i < MAX_COUNT; i++) { // @ts-ignore listofRequest.push(function (callback) { let _res; - server.putVersion(PKG_NAME, '0.1.' + String(i), racePkg(PKG_NAME)) + server + .putVersion(PKG_NAME, '0.1.' + String(i), racePkg(PKG_NAME)) .response(function (res) { _res = res; }) @@ -104,7 +111,10 @@ export default function(server) { if (response.statusCode === HTTP_STATUS.CONFLICT && ~body.error.indexOf(PRESENT)) { failcount++; } - if (response.statusCode === HTTP_STATUS.SERVICE_UNAVAILABLE && ~body.error.indexOf(UNAVAILABLE)) { + if ( + response.statusCode === HTTP_STATUS.SERVICE_UNAVAILABLE && + ~body.error.indexOf(UNAVAILABLE) + ) { failcount++; } }); @@ -120,10 +130,14 @@ export default function(server) { }); }); - afterAll(function() { - return server.getPackage(PKG_NAME).status(HTTP_STATUS.OK).then(function (body) { - expect(Object.keys(body.versions)).toHaveLength(okTotalSum); - }); + afterAll(function () { + return server + .getPackage(PKG_NAME) + .status(HTTP_STATUS.OK) + .then(function (body) { + // eslint-disable-next-line jest/no-standalone-expect + expect(Object.keys(body.versions)).toHaveLength(okTotalSum); + }); }); }); } diff --git a/test/functional/plugins/auth.ts b/test/functional/plugins/auth.ts index 4702fd436..cb4f1b9c3 100644 --- a/test/functional/plugins/auth.ts +++ b/test/functional/plugins/auth.ts @@ -1,6 +1,6 @@ -import {HTTP_STATUS, API_ERROR} from "../../../src/lib/constants"; +import { HTTP_STATUS, API_ERROR } from '../../../src/lib/constants'; -export default function(server2) { +export default function (server2) { // credentials const USER1 = 'authtest'; const USER2 = 'authtest2'; @@ -13,39 +13,48 @@ export default function(server2) { const UNEXISTING_PKG_NAME = 'test-auth-allow'; const requestAuthFail = (user, pass, message, statusCode) => { - return server2.auth(user, pass) + return server2 + .auth(user, pass) .status(statusCode) .body_error(message) - .then(function() { + .then(function () { return server2.whoami(); }) - .then(function(username) { + .then(function (username) { expect(username).toBeUndefined(); }); }; const requestAuthOk = (user, pass, regex, statusCode) => { - return server2.auth(user, pass) + return server2 + .auth(user, pass) .status(statusCode) .body_ok(regex) - .then(function() { + .then(function () { return server2.whoami(); }) - .then(function(username) { + .then(function (username) { expect(username).toBe(user); }); - }; describe('plugin authentication', () => { - describe('test users authentication', () => { - test('should not authenticate user1 with wrong password', () => { - return requestAuthFail(USER1, WRONG_PASSWORD, 'i don\'t like your password', HTTP_STATUS.UNAUTHORIZED); + return requestAuthFail( + USER1, + WRONG_PASSWORD, + "i don't like your password", + HTTP_STATUS.UNAUTHORIZED + ); }); test('should not authenticate user2 with wrong password', () => { - return requestAuthFail(USER2, WRONG_PASSWORD, 'i don\'t like your password', HTTP_STATUS.UNAUTHORIZED); + return requestAuthFail( + USER2, + WRONG_PASSWORD, + "i don't like your password", + HTTP_STATUS.UNAUTHORIZED + ); }); test('should right user2 password handled by plugin', () => { @@ -55,63 +64,68 @@ export default function(server2) { test('should right user1 password handled by plugin', () => { return requestAuthOk(USER1, CORRECT_PASSWORD, new RegExp(USER1), HTTP_STATUS.CREATED); }); - }); describe('test package access authorization', () => { - describe(`access with user ${USER1} on server2`, () => { - beforeAll(function() { - return server2.auth(USER1, CORRECT_PASSWORD) + beforeAll(function () { + return server2 + .auth(USER1, CORRECT_PASSWORD) .status(HTTP_STATUS.CREATED) .body_ok(new RegExp(USER1)); }); test(`should fails (404) on access ${UNEXISTING_PKG_NAME}`, () => { - return server2.getPackage(UNEXISTING_PKG_NAME) + return server2 + .getPackage(UNEXISTING_PKG_NAME) .status(HTTP_STATUS.NOT_FOUND) .body_error(API_ERROR.NO_PACKAGE); }); test(`should fails (403) access ${ONLY_ACCESS_BY_USER_2}`, () => { - return server2.getPackage(ONLY_ACCESS_BY_USER_2) + return server2 + .getPackage(ONLY_ACCESS_BY_USER_2) .status(HTTP_STATUS.FORBIDDEN) .body_error(API_ERROR.NOT_ALLOWED); }); test(`should fails (404) access ${AUTH_PKG_ACCESS_NAME}`, () => { - return server2.getPackage(AUTH_PKG_ACCESS_NAME) + return server2 + .getPackage(AUTH_PKG_ACCESS_NAME) .status(HTTP_STATUS.NOT_FOUND) .body_error(API_ERROR.NO_PACKAGE); }); }); describe(`access with user ${USER2} on server2`, () => { - beforeAll(function() { - return server2.auth(USER2, CORRECT_PASSWORD) + beforeAll(function () { + return server2 + .auth(USER2, CORRECT_PASSWORD) .status(HTTP_STATUS.CREATED) .body_ok(new RegExp(USER2)); }); test(`should fails (403) on access ${UNEXISTING_PKG_NAME}`, () => { - return server2.getPackage(UNEXISTING_PKG_NAME) + return server2 + .getPackage(UNEXISTING_PKG_NAME) .status(HTTP_STATUS.FORBIDDEN) .body_error(API_ERROR.NOT_ALLOWED); }); test(`should fails (403) on access ${DENY_PKG_NAME}`, () => { - return server2.getPackage(DENY_PKG_NAME) + return server2 + .getPackage(DENY_PKG_NAME) .status(HTTP_STATUS.FORBIDDEN) .body_error(API_ERROR.NOT_ALLOWED); }); test(`should fails (404) access ${AUTH_PKG_ACCESS_NAME}`, () => { - return server2.getPackage(AUTH_PKG_ACCESS_NAME) + return server2 + .getPackage(AUTH_PKG_ACCESS_NAME) .status(HTTP_STATUS.NOT_FOUND) .body_error(API_ERROR.NO_PACKAGE); }); }); - }); }); } diff --git a/test/functional/plugins/middleware.ts b/test/functional/plugins/middleware.ts index cc539ea33..49f88c56f 100644 --- a/test/functional/plugins/middleware.ts +++ b/test/functional/plugins/middleware.ts @@ -1,23 +1,25 @@ -import {HTTP_STATUS} from "../../../src/lib/constants"; +import { HTTP_STATUS } from '../../../src/lib/constants'; export default function (server2) { describe('test plugin middlewares', () => { test('should serve the registered route ES5', () => { - return server2.request({ - uri: '/test/route', - method: 'GET' - }) + return server2 + .request({ + uri: '/test/route', + method: 'GET' + }) .status(HTTP_STATUS.OK) - .body_ok('this is a custom route') - }) + .body_ok('this is a custom route'); + }); test('should serve the registered route ES6', () => { - return server2.request({ - uri: '/test/route/es6', - method: 'GET' - }) + return server2 + .request({ + uri: '/test/route/es6', + method: 'GET' + }) .status(HTTP_STATUS.OK) - .body_ok('this is a custom route es6') - }) - }) + .body_ok('this is a custom route es6'); + }); + }); } diff --git a/test/functional/readme/readme.ts b/test/functional/readme/readme.ts index b5d0a9cff..96f708874 100644 --- a/test/functional/readme/readme.ts +++ b/test/functional/readme/readme.ts @@ -1,36 +1,34 @@ -import {DEFAULT_NO_README, HTTP_STATUS} from '../../../src/lib/constants'; +import { DEFAULT_NO_README, HTTP_STATUS } from '../../../src/lib/constants'; import pkgReadmeJSON from './pkg-readme.json'; import pkgNoReadmeJSON from './pkg-no-readme.json'; import pkgNoReadmeJSONOldFormat from './pkg-readme-npm6.json'; export default function (server, server2) { - describe('should test readme', () => { const README_PKG1 = 'readme-test'; const README_PKG2 = 'readme-test-no-readme'; const README_MESSAGE = 'this is a readme'; const README_PKG3 = 'readme-test-npm6'; - beforeAll(async function() { - await server.putPackage('readme-test', pkgReadmeJSON) - .status(HTTP_STATUS.CREATED); - await server.putPackage(README_PKG2, pkgNoReadmeJSON) - .status(HTTP_STATUS.CREATED); - await server.putPackage(README_PKG3, pkgNoReadmeJSONOldFormat) - .status(HTTP_STATUS.CREATED); + beforeAll(async function () { + await server.putPackage('readme-test', pkgReadmeJSON).status(HTTP_STATUS.CREATED); + await server.putPackage(README_PKG2, pkgNoReadmeJSON).status(HTTP_STATUS.CREATED); + await server.putPackage(README_PKG3, pkgNoReadmeJSONOldFormat).status(HTTP_STATUS.CREATED); }); test('add pkg', () => {}); describe('should check readme file', () => { const matchReadme = (serverRef, pkgName = README_PKG1, readmeMessage = README_MESSAGE) => { - return serverRef.request({ - uri: `/-/verdaccio/package/readme/${pkgName}` - }).status(HTTP_STATUS.OK).then(function(body) { - - expect(body).toEqual(`

${readmeMessage}

`); - }); + return serverRef + .request({ + uri: `/-/verdaccio/package/readme/${pkgName}` + }) + .status(HTTP_STATUS.OK) + .then(function (body) { + expect(body).toEqual(`

${readmeMessage}

`); + }); }; test('should fetch server2 over uplink server1', () => { @@ -52,8 +50,6 @@ export default function (server, server2) { test('should fetch not found readme package on local server1', () => { return matchReadme(server2, README_PKG2, DEFAULT_NO_README); }); - - }); }); } diff --git a/test/functional/sanity/incomplete.ts b/test/functional/sanity/incomplete.ts index a320a6206..d3c890e12 100644 --- a/test/functional/sanity/incomplete.ts +++ b/test/functional/sanity/incomplete.ts @@ -1,33 +1,32 @@ -import {API_ERROR, HEADER_TYPE, HTTP_STATUS} from '../../../src/lib/constants'; -import {DOMAIN_SERVERS, PORT_SERVER_APP} from '../config.functional'; +import { API_ERROR, HEADER_TYPE, HTTP_STATUS } from '../../../src/lib/constants'; +import { DOMAIN_SERVERS, PORT_SERVER_APP } from '../config.functional'; const defaultPkg = { - 'name': 'testexp-incomplete', - 'versions': { + name: 'testexp-incomplete', + versions: { '0.1.0': { - 'name': 'testexp_tags', - 'version': '0.1.0', - 'dist': { - 'shasum': 'fake', - 'tarball': `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/testexp-incomplete/-/content-length.tar.gz`, - }, + name: 'testexp_tags', + version: '0.1.0', + dist: { + shasum: 'fake', + tarball: `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/testexp-incomplete/-/content-length.tar.gz` + } }, '0.1.1': { - 'name': 'testexp_tags', - 'version': '0.1.1', - 'dist': { - 'shasum': 'fake', - 'tarball': `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/testexp-incomplete/-/chunked.tar.gz`, - }, - }, - }, + name: 'testexp_tags', + version: '0.1.1', + dist: { + shasum: 'fake', + tarball: `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/testexp-incomplete/-/chunked.tar.gz` + } + } + } }; export default function (server, express) { const listofCalls = [HEADER_TYPE.CONTENT_LENGTH, 'chunked']; describe('test send incomplete packages', () => { - beforeAll(function () { express.get('/testexp-incomplete', function (_, res) { res.send(defaultPkg); @@ -35,7 +34,7 @@ export default function (server, express) { }); listofCalls.forEach((type) => { - test(`should not store tarballs / ${type}`, callback => { + test(`should not store tarballs / ${type}`, (callback) => { let called; express.get(`/testexp-incomplete/-/${type}.tar.gz`, function (_, response) { if (called) { @@ -56,18 +55,21 @@ export default function (server, express) { }, 10); }); - server.request({uri: '/testexp-incomplete/-/' + type + '.tar.gz'}) + server + .request({ uri: '/testexp-incomplete/-/' + type + '.tar.gz' }) .status(HTTP_STATUS.OK) .response(function (res) { if (type !== 'chunked') { expect(parseInt(res.headers[HEADER_TYPE.CONTENT_LENGTH], 10)).toBe(1e6); } - }).then(function (body) { + }) + .then(function (body) { expect(body).toMatch(/test test test/); }); function cb() { - server.request({uri: '/testexp-incomplete/-/' + type + '.tar.gz'}) + server + .request({ uri: '/testexp-incomplete/-/' + type + '.tar.gz' }) .body_error(API_ERROR.INTERNAL_SERVER_ERROR) .then(function () { callback(); diff --git a/test/functional/sanity/mirror.ts b/test/functional/sanity/mirror.ts index 42ce6da43..f06d5f318 100644 --- a/test/functional/sanity/mirror.ts +++ b/test/functional/sanity/mirror.ts @@ -1,15 +1,16 @@ -import {readFile} from '../lib/test.utils'; -import {API_MESSAGE, HTTP_STATUS} from "../../../src/lib/constants"; -import generatePkg from '../fixtures/package'; -import {TARBALL} from '../config.functional'; +import { readFile } from '../lib/test.utils'; +import { API_MESSAGE, HTTP_STATUS } from '../../../src/lib/constants'; +import generatePkg from '../fixtures/package'; +import { TARBALL } from '../config.functional'; -const getBinary = () => readFile('../fixtures/binary'); +const getBinary = () => readFile('../fixtures/binary'); export default function (server, server2) { - describe('anti-loop testing', () => { test('testing anti-loop', () => { - return server2.getPackage('testloop').status(HTTP_STATUS.NOT_FOUND) + return server2 + .getPackage('testloop') + .status(HTTP_STATUS.NOT_FOUND) .body_error(/no such package/); }); }); @@ -23,7 +24,8 @@ export default function (server, server2) { describe(`testing mirror for ${pkg}`, () => { beforeAll(function () { - return server2.putPackage(pkg, generatePkg(pkg)) + return server2 + .putPackage(pkg, generatePkg(pkg)) .status(HTTP_STATUS.CREATED) .body_ok(API_MESSAGE.PKG_CREATED); }); @@ -32,7 +34,8 @@ export default function (server, server2) { describe(`${pkg}`, () => { beforeAll(function () { - return server2.putVersion(pkg, '0.1.1', generatePkg(pkg)) + return server2 + .putVersion(pkg, '0.1.1', generatePkg(pkg)) .status(HTTP_STATUS.CREATED) .body_ok(/published/); }); @@ -45,7 +48,8 @@ export default function (server, server2) { describe('should put a tarball', () => { beforeAll(function () { - return server2.putTarball(pkg, TARBALL, getBinary()) + return server2 + .putTarball(pkg, TARBALL, getBinary()) .status(HTTP_STATUS.CREATED) .body_ok(/.*/); }); @@ -53,7 +57,8 @@ export default function (server, server2) { test(`should ${prefix} uploading new tarball`, () => {}); test(`should ${prefix} downloading tarball from server2`, () => { - return server2.getTarball(pkg, TARBALL) + return server2 + .getTarball(pkg, TARBALL) .status(HTTP_STATUS.OK) .then(function (body) { expect(body).toEqual(getBinary()); @@ -65,7 +70,8 @@ export default function (server, server2) { }); test(`should ${prefix} downloading tarball from server1`, () => { - return server.getTarball(pkg, TARBALL) + return server + .getTarball(pkg, TARBALL) .status(HTTP_STATUS.OK) .then(function (body) { expect(body).toEqual(getBinary()); diff --git a/test/functional/sanity/nullstorage.ts b/test/functional/sanity/nullstorage.ts index 91fde1bbc..8e510279a 100644 --- a/test/functional/sanity/nullstorage.ts +++ b/test/functional/sanity/nullstorage.ts @@ -1,72 +1,86 @@ -import {readFile} from '../lib/test.utils'; -import {createTarballHash} from "../../../src/lib/crypto-utils"; -import {API_ERROR, HTTP_STATUS} from "../../../src/lib/constants"; -import {DOMAIN_SERVERS, PORT_SERVER_1, TARBALL} from '../config.functional'; -import generatePkg from '../fixtures/package'; -import {DIST_TAGS} from '../../../src/lib/constants'; +import { readFile } from '../lib/test.utils'; +import { createTarballHash } from '../../../src/lib/crypto-utils'; +import { API_ERROR, HTTP_STATUS } from '../../../src/lib/constants'; +import { DOMAIN_SERVERS, PORT_SERVER_1, TARBALL } from '../config.functional'; +import generatePkg from '../fixtures/package'; +import { DIST_TAGS } from '../../../src/lib/constants'; function getBinary() { return readFile('../fixtures/binary'); } export default function (server, server2) { - const PKG_NAME = 'test-nullstorage2'; const PKG_VERSION = '0.0.1'; // const TARBALL = `${PKG_NAME}-file.name`; describe('should test a scenario when tarball is being fetch from uplink', () => { - describe(`should check whether ${PKG_NAME} is on server1`, () => { test('should fails on fetch non-existent package on server1', () => { - return server.getPackage('test-nullstorage-nonexist').status(HTTP_STATUS.NOT_FOUND) + return server + .getPackage('test-nullstorage-nonexist') + .status(HTTP_STATUS.NOT_FOUND) .body_error(API_ERROR.NO_PACKAGE); }); }); describe(`should check whether ${PKG_NAME} is on server2`, () => { - beforeAll(function() { + beforeAll(function () { return server2.addPackage(PKG_NAME); }); - test('should create a new package on server2', () => {/* test for before() */}); + test('should create a new package on server2', () => { + /* test for before() */ + }); test('should fails on download a non existent tarball from server1', () => { - return server.getTarball(PKG_NAME, TARBALL) + return server + .getTarball(PKG_NAME, TARBALL) .status(HTTP_STATUS.NOT_FOUND) .body_error(/no such file/); }); describe(`should succesfully publish ${PKG_NAME} package on server2`, () => { - beforeAll(function() { - return server2.putTarball(PKG_NAME, TARBALL, getBinary()).status(HTTP_STATUS.CREATED).body_ok(/.*/); + beforeAll(function () { + return server2 + .putTarball(PKG_NAME, TARBALL, getBinary()) + .status(HTTP_STATUS.CREATED) + .body_ok(/.*/); }); - beforeAll(function() { + beforeAll(function () { let pkg = generatePkg(PKG_NAME); pkg.dist.shasum = createTarballHash().update(getBinary()).digest('hex'); - return server2.putVersion(PKG_NAME, PKG_VERSION, pkg) - .status(HTTP_STATUS.CREATED).body_ok(/published/); + return server2 + .putVersion(PKG_NAME, PKG_VERSION, pkg) + .status(HTTP_STATUS.CREATED) + .body_ok(/published/); }); - test(`should publish a new version for ${PKG_NAME} on server 2`, () => {/* test for before() */}); + test(`should publish a new version for ${PKG_NAME} on server 2`, () => { + /* test for before() */ + }); test(`should fetch the newly created published tarball for ${PKG_NAME} from server1 on server2`, () => { - return server.getTarball(PKG_NAME, TARBALL) + return server + .getTarball(PKG_NAME, TARBALL) .status(HTTP_STATUS.OK) - .then(function(body) { + .then(function (body) { expect(body).toEqual(getBinary()); }); }); test(`should fetch metadata for ${PKG_NAME} match from server1`, () => { - return server.getPackage(PKG_NAME) + return server + .getPackage(PKG_NAME) .status(HTTP_STATUS.OK) - .then(function(body) { + .then(function (body) { expect(body.name).toBe(PKG_NAME); expect(body.versions[PKG_VERSION].name).toBe(PKG_NAME); - expect(body.versions[PKG_VERSION].dist.tarball).toBe(`http://${DOMAIN_SERVERS}:${PORT_SERVER_1}/${PKG_NAME}/-/${TARBALL}`); - expect(body[DIST_TAGS]).toEqual({latest: PKG_VERSION}); + expect(body.versions[PKG_VERSION].dist.tarball).toBe( + `http://${DOMAIN_SERVERS}:${PORT_SERVER_1}/${PKG_NAME}/-/${TARBALL}` + ); + expect(body[DIST_TAGS]).toEqual({ latest: PKG_VERSION }); }); }); }); diff --git a/test/functional/sanity/racycrash.ts b/test/functional/sanity/racycrash.ts index bf8d557be..86a303bd3 100644 --- a/test/functional/sanity/racycrash.ts +++ b/test/functional/sanity/racycrash.ts @@ -1,38 +1,37 @@ -import {DOMAIN_SERVERS, PORT_SERVER_APP} from '../config.functional'; -import {API_ERROR, HEADER_TYPE, HTTP_STATUS} from '../../../src/lib/constants'; - -export default function(server, express) { +import { DOMAIN_SERVERS, PORT_SERVER_APP } from '../config.functional'; +import { API_ERROR, HEADER_TYPE, HTTP_STATUS } from '../../../src/lib/constants'; +export default function (server, express) { describe('shoul test for unexpected client hangs', () => { let handleResponseTarball; - beforeAll(function() { - express.get('/testexp-racycrash', function(request, response) { + beforeAll(function () { + express.get('/testexp-racycrash', function (request, response) { response.send({ - 'name': 'testexp-racycrash', - 'versions': { + name: 'testexp-racycrash', + versions: { '0.1.0': { - 'name': 'testexp_tags', - 'version': '0.1.0', - 'dist': { - 'shasum': 'fake', - 'tarball': `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/testexp-racycrash/-/test.tar.gz`, - }, - }, - }, + name: 'testexp_tags', + version: '0.1.0', + dist: { + shasum: 'fake', + tarball: `http://${DOMAIN_SERVERS}:${PORT_SERVER_APP}/testexp-racycrash/-/test.tar.gz` + } + } + } }); }); - express.get('/testexp-racycrash/-/test.tar.gz', function(request, response) { + express.get('/testexp-racycrash/-/test.tar.gz', function (request, response) { handleResponseTarball(response); }); }); - test('should not crash on error if client disconnects', callback => { - handleResponseTarball = function(res) { + test('should not crash on error if client disconnects', (callback) => { + handleResponseTarball = function (res) { res.header(HEADER_TYPE.CONTENT_LENGTH, 1e6); res.write('test test test'); - setTimeout(function() { + setTimeout(function () { res.write('-'); // destroy the connection res.socket.destroy(); @@ -40,27 +39,28 @@ export default function(server, express) { }, HTTP_STATUS.OK); }; - server.request({uri: '/testexp-racycrash/-/test.tar.gz'}) - .then(function(body) { - expect(body).toEqual('test test test'); - }); + server.request({ uri: '/testexp-racycrash/-/test.tar.gz' }).then(function (body) { + expect(body).toEqual('test test test'); + }); function cb() { // test for NOT crashing - server.request({uri: '/testexp-racycrash'}) + server + .request({ uri: '/testexp-racycrash' }) .status(HTTP_STATUS.OK) - .then(function() { + .then(function () { callback(); }); } }); test('should not store tarball', () => { - handleResponseTarball = function(res) { + handleResponseTarball = function (res) { res.socket.destroy(); }; - return server.request({uri: '/testexp-racycrash/-/test.tar.gz'}) + return server + .request({ uri: '/testexp-racycrash/-/test.tar.gz' }) .body_error(API_ERROR.INTERNAL_SERVER_ERROR); }); }); diff --git a/test/functional/sanity/security.ts b/test/functional/sanity/security.ts index c366a655d..1caec5b09 100644 --- a/test/functional/sanity/security.ts +++ b/test/functional/sanity/security.ts @@ -1,67 +1,76 @@ import _ from 'lodash'; -import {HTTP_STATUS} from '../../../src/lib/constants'; - -export default function(server) { +import { HTTP_STATUS } from '../../../src/lib/constants'; +export default function (server) { describe('should test security on endpoints', () => { beforeAll(function () { return server.addPackage('testpkg-sec'); }); test('should fails on fetch bad pkg #1', () => { - return server.getPackage('__proto__') + return server + .getPackage('__proto__') .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid package/); }); test('should fails on fetch bad pkg #2', () => { - return server.getPackage('__proto__') + return server + .getPackage('__proto__') .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid package/); }); test('should do not fails on __proto__, connect stuff', () => { - return server.request({uri: '/testpkg-sec?__proto__=1'}) - .then(function (body) { - // test for NOT outputting stack trace - expect(_.isNil(body) || _.isObject(body) || body.indexOf('node_modules')).toBeTruthy(); + return server.request({ uri: '/testpkg-sec?__proto__=1' }).then(function (body) { + // test for NOT outputting stack trace + expect(_.isNil(body) || _.isObject(body) || body.indexOf('node_modules')).toBeTruthy(); - // test for NOT crashing - return server.request({uri: '/testpkg-sec'}).status(HTTP_STATUS.OK); - }); + // test for NOT crashing + return server.request({ uri: '/testpkg-sec' }).status(HTTP_STATUS.OK); + }); }); test('should fails and do not return __proto__ as an attachment', () => { - return server.request({uri: '/testpkg-sec/-/__proto__'}) + return server + .request({ uri: '/testpkg-sec/-/__proto__' }) .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid filename/); }); test('should fails on fetch silly things - reading #1', () => { - return server.request({uri: '/testpkg-sec/-/../../../../../../../../etc/passwd'}) + return server + .request({ uri: '/testpkg-sec/-/../../../../../../../../etc/passwd' }) .status(HTTP_STATUS.NOT_FOUND); }); test('should fails on fetch silly things - reading #2', () => { - return server.request({uri: '/testpkg-sec/-/%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd'}) + return server + .request({ + uri: + '/testpkg-sec/-/%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd' + }) .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid filename/); }); test('should fails on fetch silly things - writing #1', () => { - return server.putTarball('testpkg-sec', '__proto__', '{}') + return server + .putTarball('testpkg-sec', '__proto__', '{}') .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid filename/); }); test('should fails on fetch silly things - writing #3', () => { - return server.putTarball('testpkg-sec', 'node_modules', '{}') + return server + .putTarball('testpkg-sec', 'node_modules', '{}') .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid filename/); }); test('should fails on fetch silly things - writing #4', () => { - return server.putTarball('testpkg-sec', '../testpkg.tgz', '{}') + return server + .putTarball('testpkg-sec', '../testpkg.tgz', '{}') .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid filename/); }); diff --git a/test/functional/scenarios/gh29.ts b/test/functional/scenarios/gh29.ts index 1a66efbe6..49b5135b6 100644 --- a/test/functional/scenarios/gh29.ts +++ b/test/functional/scenarios/gh29.ts @@ -1,12 +1,12 @@ import fs from 'fs'; import path from 'path'; -import {TARBALL} from '../config.functional'; -import {HTTP_STATUS} from "../../../src/lib/constants"; -import {createTarballHash} from "../../../src/lib/crypto-utils"; +import { TARBALL } from '../config.functional'; +import { HTTP_STATUS } from '../../../src/lib/constants'; +import { createTarballHash } from '../../../src/lib/crypto-utils'; import requirePackage from '../fixtures/package'; function readfile(filePath) { - const folder = path.join(__dirname , filePath); + const folder = path.join(__dirname, filePath); return fs.readFileSync(folder); } @@ -17,15 +17,17 @@ const pkgName = 'testpkg-gh29'; export default function (server, server2) { describe('pkg-gh29 #1', () => { test('downloading non-existent tarball #1 / srv2', () => { - return server2.getTarball(pkgName, TARBALL) + return server2 + .getTarball(pkgName, TARBALL) .status(HTTP_STATUS.NOT_FOUND) .body_error(/no such package/); }); }); describe('pkg-gh29 #2', () => { - beforeAll(function() { - return server.putPackage(pkgName, requirePackage(pkgName)) + beforeAll(function () { + return server + .putPackage(pkgName, requirePackage(pkgName)) .status(HTTP_STATUS.CREATED) .body_ok(/created new package/); }); @@ -33,14 +35,16 @@ export default function (server, server2) { test('creating new package / srv1', () => {}); test('downloading non-existent tarball #2 / srv2', () => { - return server2.getTarball(pkgName, TARBALL) + return server2 + .getTarball(pkgName, TARBALL) .status(HTTP_STATUS.NOT_FOUND) .body_error(/no such file available/); }); describe('tarball', () => { - beforeAll(function() { - return server.putTarball(pkgName, TARBALL, readfile(binary)) + beforeAll(function () { + return server + .putTarball(pkgName, TARBALL, readfile(binary)) .status(HTTP_STATUS.CREATED) .body_ok(/.*/); }); @@ -48,10 +52,11 @@ export default function (server, server2) { test('uploading new tarball / srv1', () => {}); describe('pkg version', () => { - beforeAll(function() { + beforeAll(function () { const pkg = requirePackage(pkgName); pkg.dist.shasum = createTarballHash().update(readfile(binary)).digest('hex'); - return server.putVersion(pkgName, '0.0.1', pkg) + return server + .putVersion(pkgName, '0.0.1', pkg) .status(HTTP_STATUS.CREATED) .body_ok(/published/); }); @@ -59,9 +64,10 @@ export default function (server, server2) { test('uploading new package version / srv1', () => {}); test('downloading newly created tarball / srv2', () => { - return server2.getTarball(pkgName, TARBALL) + return server2 + .getTarball(pkgName, TARBALL) .status(HTTP_STATUS.OK) - .then(function(body) { + .then(function (body) { expect(body).toEqual(readfile(binary)); }); }); diff --git a/test/functional/search/simple.search.ts b/test/functional/search/simple.search.ts index 0ddfb09d3..6544859aa 100644 --- a/test/functional/search/simple.search.ts +++ b/test/functional/search/simple.search.ts @@ -1,13 +1,13 @@ -import {API_MESSAGE, HTTP_STATUS} from '../../../src/lib/constants'; +import { API_MESSAGE, HTTP_STATUS } from '../../../src/lib/constants'; import pkgExample from './search.json'; -export default function(server, server2, express) { - +export default function (server, server2, express) { describe('should test search a published package', () => { const PKG_NAME = 'testpkg-search'; - beforeAll(function() { - return server.putPackage(PKG_NAME, pkgExample) + beforeAll(function () { + return server + .putPackage(PKG_NAME, pkgExample) .status(HTTP_STATUS.CREATED) .body_ok(API_MESSAGE.PKG_CREATED); }); @@ -15,49 +15,47 @@ export default function(server, server2, express) { describe('should test simple search', () => { const check = (medatada) => { medatada[PKG_NAME].time.modified = '2014-10-02T07:07:51.000Z'; - expect(medatada[PKG_NAME]).toEqual( - { - 'name': PKG_NAME, - 'description': '', - 'author': '', - 'license': 'ISC', - 'dist-tags': { - latest: '0.0.1' - }, - 'maintainers': [{ + expect(medatada[PKG_NAME]).toEqual({ + name: PKG_NAME, + description: '', + author: '', + license: 'ISC', + 'dist-tags': { + latest: '0.0.1' + }, + maintainers: [ + { name: 'alex', email: 'user@domain.com' - }], - 'readmeFilename': '', - 'time': { - modified: '2014-10-02T07:07:51.000Z' - }, - 'versions': { - "0.0.1": "latest" - }, - 'repository': { - type: 'git', url: ''} - }); + } + ], + readmeFilename: '', + time: { + modified: '2014-10-02T07:07:51.000Z' + }, + versions: { + '0.0.1': 'latest' + }, + repository: { + type: 'git', + url: '' + } + }); }; - beforeAll(function() { + beforeAll(function () { express.get('/-/all', (req, res) => { res.send({}); }); }); test('server1 - search', () => { - return server.request({uri: '/-/all'}) - .status(HTTP_STATUS.OK) - .then(check); + return server.request({ uri: '/-/all' }).status(HTTP_STATUS.OK).then(check); }); test('server2 - search', () => { - return server2.request({uri: '/-/all'}) - .status(HTTP_STATUS.OK) - .then(check); + return server2.request({ uri: '/-/all' }).status(HTTP_STATUS.OK).then(check); }); - }); }); } diff --git a/test/functional/tags/addtag.ts b/test/functional/tags/addtag.ts index dc311eb33..4e7e108af 100644 --- a/test/functional/tags/addtag.ts +++ b/test/functional/tags/addtag.ts @@ -1,46 +1,56 @@ -import {readFile} from '../lib/test.utils'; -import {API_ERROR, HTTP_STATUS, CHARACTER_ENCODING} from "../../../src/lib/constants"; +import { readFile } from '../lib/test.utils'; +import { API_ERROR, HTTP_STATUS, CHARACTER_ENCODING } from '../../../src/lib/constants'; const readTags = () => readFile('../fixtures/publish.json5'); -export default function(server) { - +export default function (server) { describe('should test add tag', () => { - const PKG_NAME = 'testpkg-tag'; const PKG_VERSION = '0.0.1'; test('should fails on add tag to non existing package', () => { - return server.addTag(PKG_NAME, 'tagtagtag', PKG_VERSION) - .status(HTTP_STATUS.NOT_FOUND).body_error(API_ERROR.NO_PACKAGE); + return server + .addTag(PKG_NAME, 'tagtagtag', PKG_VERSION) + .status(HTTP_STATUS.NOT_FOUND) + .body_error(API_ERROR.NO_PACKAGE); }); describe('should test add tag to a package', () => { - beforeAll(function() { - return server.putPackage(PKG_NAME, - JSON.parse(readTags().toString(CHARACTER_ENCODING.UTF8).replace(/__NAME__/g, PKG_NAME) - .replace(/__VERSION__/g, PKG_VERSION)) - ).status(HTTP_STATUS.CREATED); + beforeAll(function () { + return server + .putPackage( + PKG_NAME, + JSON.parse( + readTags() + .toString(CHARACTER_ENCODING.UTF8) + .replace(/__NAME__/g, PKG_NAME) + .replace(/__VERSION__/g, PKG_VERSION) + ) + ) + .status(HTTP_STATUS.CREATED); }); describe('should test valid formats tags', () => { test('should fails on add a tag that do not exist', () => { - return server.addTag(PKG_NAME, 'tagtagtag', '4.0.0-no-exist') + return server + .addTag(PKG_NAME, 'tagtagtag', '4.0.0-no-exist') .status(HTTP_STATUS.NOT_FOUND) .body_error(API_ERROR.VERSION_NOT_EXIST); }); test('should add tag succesfully minor version', () => { - return server.addTag(PKG_NAME, 'tagtagtag', PKG_VERSION) + return server + .addTag(PKG_NAME, 'tagtagtag', PKG_VERSION) .status(HTTP_STATUS.CREATED) .body_ok(/tagged/); }); }); describe('should test handle invalid tag and version names', () => { - const INVALID_TAG ='tag/tag/tag'; - const handleInvalidTag = function(tag, version) { - return server.addTag(PKG_NAME, tag, version) + const INVALID_TAG = 'tag/tag/tag'; + const handleInvalidTag = function (tag, version) { + return server + .addTag(PKG_NAME, tag, version) .status(HTTP_STATUS.FORBIDDEN) .body_error(/invalid tag/); }; diff --git a/test/functional/tags/dist-tags-merge.ts b/test/functional/tags/dist-tags-merge.ts index 45c58b2c7..4dacb3d06 100644 --- a/test/functional/tags/dist-tags-merge.ts +++ b/test/functional/tags/dist-tags-merge.ts @@ -1,49 +1,53 @@ -import {generateSha} from '../lib/test.utils'; -import {API_MESSAGE, HTTP_STATUS} from '../../../src/lib/constants'; -import {DOMAIN_SERVERS, PORT_SERVER_1, PORT_SERVER_2, PORT_SERVER_3} from '../config.functional'; -import {DIST_TAGS} from '../../../src/lib/constants'; +import { generateSha } from '../lib/test.utils'; +import { API_MESSAGE, HTTP_STATUS } from '../../../src/lib/constants'; +import { DOMAIN_SERVERS, PORT_SERVER_1, PORT_SERVER_2, PORT_SERVER_3 } from '../config.functional'; +import { DIST_TAGS } from '../../../src/lib/constants'; import pkgExample from './dist-tags-merge.json'; -export default function(server, server2, server3) { - +export default function (server, server2, server3) { describe('should test preserve tags when publishing something', () => { const PKG_NAME = 'testpkg-preserve'; const PKG_VERSION = '0.0.1'; - beforeAll(function() { - return server.putPackage(PKG_NAME, pkgExample) + beforeAll(function () { + return server + .putPackage(PKG_NAME, pkgExample) .status(HTTP_STATUS.CREATED) .body_ok(API_MESSAGE.PKG_CREATED); }); describe('should check sha integrity', () => { - const matchTarBallSha = (server) => { - return server.getTarball(PKG_NAME, `${PKG_NAME}-${PKG_VERSION}.tgz`) + return server + .getTarball(PKG_NAME, `${PKG_NAME}-${PKG_VERSION}.tgz`) .status(HTTP_STATUS.OK) - .then(function(body) { + .then(function (body) { // not real sha due to utf8 conversion expect(generateSha(body)).toBe(pkgExample.versions[PKG_VERSION].dist.shasum); }); }; - test('server1 should match with sha key from published package', () => matchTarBallSha(server)); - test('server2 should match with sha key from published package', () => matchTarBallSha(server2)); - + test('server1 should match with sha key from published package', () => + matchTarBallSha(server)); + test('server2 should match with sha key from published package', () => + matchTarBallSha(server2)); }); describe('should match dist-tags', () => { const matchDisTags = (verdaccioServer, port) => { - return verdaccioServer.getPackage(PKG_NAME) + return verdaccioServer + .getPackage(PKG_NAME) .status(HTTP_STATUS.OK) - .then(function(body) { + .then(function (body) { expect(body.name).toBe(PKG_NAME); expect(body.time).toBeDefined(); expect(body.time[PKG_VERSION]).toBeDefined(); expect(body.time).toBeDefined(); expect(body.versions[PKG_VERSION].name).toBe(PKG_NAME); - expect(body.versions[PKG_VERSION].dist.tarball).toBe(`http://${DOMAIN_SERVERS}:${port}/${PKG_NAME}/-/${PKG_NAME}-${PKG_VERSION}.tgz`); - expect(body[DIST_TAGS]).toEqual({foo: PKG_VERSION, latest: PKG_VERSION}); + expect(body.versions[PKG_VERSION].dist.tarball).toBe( + `http://${DOMAIN_SERVERS}:${port}/${PKG_NAME}/-/${PKG_NAME}-${PKG_VERSION}.tgz` + ); + expect(body[DIST_TAGS]).toEqual({ foo: PKG_VERSION, latest: PKG_VERSION }); }); }; diff --git a/test/functional/tags/tags.ts b/test/functional/tags/tags.ts index f7f861568..01c17c2ba 100644 --- a/test/functional/tags/tags.ts +++ b/test/functional/tags/tags.ts @@ -1,31 +1,35 @@ - import _ from 'lodash'; -import {readFile} from '../lib/test.utils'; +import { readFile } from '../lib/test.utils'; import { HTTP_STATUS } from '../../../src/lib/constants'; const readTags = () => readFile('../fixtures/tags.json'); -export default function(server, express) { - +export default function (server, express) { test('tags - testing for 404', () => { - return server.getPackage('testexp_tags') - // shouldn't exist yet - .status(HTTP_STATUS.NOT_FOUND) - .body_error(/no such package/); + return ( + server + .getPackage('testexp_tags') + // shouldn't exist yet + .status(HTTP_STATUS.NOT_FOUND) + .body_error(/no such package/) + ); }); describe('tags', () => { - beforeAll(function() { - express.get('/testexp_tags', function(req, res) { - let f = readTags().toString().replace(/__NAME__/g, 'testexp_tags'); + beforeAll(function () { + express.get('/testexp_tags', function (req, res) { + let f = readTags() + .toString() + .replace(/__NAME__/g, 'testexp_tags'); res.send(JSON.parse(f)); }); }); test('fetching package again', () => { - return server.getPackage('testexp_tags') + return server + .getPackage('testexp_tags') .status(200) - .then(function(body) { + .then(function (body) { expect(_.isObject(body.versions['1.1.0'])).toBe(true); // note: 5.4.3 is invalid tag, 0.1.3alpha is highest semver expect(body['dist-tags'].latest).toEqual('1.1.0'); @@ -35,11 +39,12 @@ export default function(server, express) { const versions = ['0.1.1alpha', '0.1.1-alpha', '0000.00001.001-alpha']; - versions.forEach(function(ver) { - test('fetching '+ver, () => { - return server.request({uri: '/testexp_tags/'+ver}) + versions.forEach(function (ver) { + test('fetching ' + ver, () => { + return server + .request({ uri: '/testexp_tags/' + ver }) .status(200) - .then(function(body) { + .then(function (body) { expect(body.version).toEqual('0.1.1alpha'); }); }); @@ -47,117 +52,146 @@ export default function(server, express) { }); describe('dist-tags methods', () => { - - beforeAll(function() { - - express.get('/testexp_tags2', function(req, res) { - let f = readTags().toString().replace(/__NAME__/g, 'testexp_tags2'); + beforeAll(function () { + express.get('/testexp_tags2', function (req, res) { + let f = readTags() + .toString() + .replace(/__NAME__/g, 'testexp_tags2'); res.send(JSON.parse(f)); }); - }); // populate cache - beforeAll(function() { + beforeAll(function () { return server.getPackage('testexp_tags2').status(200); }); test('fetching tags', () => { - return server.request({ - method: 'GET', - uri: '/-/package/testexp_tags2/dist-tags', - }).status(200).then(function(body) { - const expected = { - latest: "1.1.0" - }; - - expect(body).toEqual(expected); - }); - }); - - test('merging tags', () => { - return server.request({ - method: 'POST', - uri: '/-/package/testexp_tags2/dist-tags', - json: { - foo: '0.1.2', - quux: '0.1.0', - }, - }).status(201).body_ok(/updated/).then(function() { - return server.request({ + return server + .request({ method: 'GET', - uri: '/-/package/testexp_tags2/dist-tags', - }).status(200).then(function(body) { + uri: '/-/package/testexp_tags2/dist-tags' + }) + .status(200) + .then(function (body) { const expected = { - "latest": "1.1.0", - "foo": "0.1.2", - "quux": "0.1.0" - }; - - expect(body).toEqual(expected); - }); - }); - }); - - test('should add a dist-tag called foo', () => { - return server.request({ - method: 'PUT', - uri: '/-/package/testexp_tags2/dist-tags/foo', - json: '0.1.3alpha', - }).status(201).body_ok(/tagged/).then(function() { - return server.request({ - method: 'GET', - uri: '/-/package/testexp_tags2/dist-tags', - }).status(200).then(function(body) { - const expected = { - foo: '0.1.3alpha', - quux: '0.1.0', latest: '1.1.0' }; expect(body).toEqual(expected); }); - }); + }); + + test('merging tags', () => { + return server + .request({ + method: 'POST', + uri: '/-/package/testexp_tags2/dist-tags', + json: { + foo: '0.1.2', + quux: '0.1.0' + } + }) + .status(201) + .body_ok(/updated/) + .then(function () { + return server + .request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags' + }) + .status(200) + .then(function (body) { + const expected = { + latest: '1.1.0', + foo: '0.1.2', + quux: '0.1.0' + }; + + expect(body).toEqual(expected); + }); + }); + }); + + test('should add a dist-tag called foo', () => { + return server + .request({ + method: 'PUT', + uri: '/-/package/testexp_tags2/dist-tags/foo', + json: '0.1.3alpha' + }) + .status(201) + .body_ok(/tagged/) + .then(function () { + return server + .request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags' + }) + .status(200) + .then(function (body) { + const expected = { + foo: '0.1.3alpha', + quux: '0.1.0', + latest: '1.1.0' + }; + + expect(body).toEqual(expected); + }); + }); }); test('should remove a dis-tag called quux', () => { - return server.request({ - method: 'DELETE', - uri: '/-/package/testexp_tags2/dist-tags/latest', - }).status(201).body_ok(/removed/).then(function() { - return server.request({ - method: 'GET', - uri: '/-/package/testexp_tags2/dist-tags', - }).status(200).then(function(body) { - const expected = { - latest: '1.1.0', - "quux": "0.1.0", - foo: "0.1.3alpha" - }; + return server + .request({ + method: 'DELETE', + uri: '/-/package/testexp_tags2/dist-tags/latest' + }) + .status(201) + .body_ok(/removed/) + .then(function () { + return server + .request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags' + }) + .status(200) + .then(function (body) { + const expected = { + latest: '1.1.0', + quux: '0.1.0', + foo: '0.1.3alpha' + }; - expect(body).toEqual(expected); + expect(body).toEqual(expected); + }); }); - }); }); test('should remove a dis-tag called foo', () => { - return server.request({ - method: 'DELETE', - uri: '/-/package/testexp_tags2/dist-tags/foo', - }).status(201).body_ok(/removed/).then(function() { - return server.request({ - method: 'GET', - uri: '/-/package/testexp_tags2/dist-tags', - }).status(200).then(function(body) { - const expected = { - latest: '1.1.0', - "quux": "0.1.0" - }; + return server + .request({ + method: 'DELETE', + uri: '/-/package/testexp_tags2/dist-tags/foo' + }) + .status(201) + .body_ok(/removed/) + .then(function () { + return server + .request({ + method: 'GET', + uri: '/-/package/testexp_tags2/dist-tags' + }) + .status(200) + .then(function (body) { + const expected = { + latest: '1.1.0', + quux: '0.1.0' + }; - expect(body).toEqual(expected); + expect(body).toEqual(expected); + }); }); - }); }); - }); } diff --git a/test/functional/uplinks/cache.ts b/test/functional/uplinks/cache.ts index 70e336f25..f65d373db 100644 --- a/test/functional/uplinks/cache.ts +++ b/test/functional/uplinks/cache.ts @@ -2,8 +2,8 @@ import fs from 'fs'; import path from 'path'; import crypto from 'crypto'; import { readFile } from '../lib/test.utils'; -import {HTTP_STATUS} from "../../../src/lib/constants"; -import {TARBALL} from '../config.functional'; +import { HTTP_STATUS } from '../../../src/lib/constants'; +import { TARBALL } from '../config.functional'; import { createTarballHash } from '../../../src/lib/crypto-utils'; import requirePackage from '../fixtures/package'; @@ -23,16 +23,15 @@ function isCached(pkgName, tarballName) { } export default function (server, server2, server3) { - describe('storage tarball cache test', () => { - // more info #131 beforeAll(function () { return server.addPackage(PKG_GH131); }); beforeAll(function () { - return server.putTarball(PKG_GH131, TARBALL, getBinary()) + return server + .putTarball(PKG_GH131, TARBALL, getBinary()) .status(HTTP_STATUS.CREATED) .body_ok(/.*/); }); @@ -41,7 +40,8 @@ export default function (server, server2, server3) { const pkg = requirePackage(PKG_GH131); pkg.dist.shasum = crypto.createHash('sha1').update(getBinary()).digest('hex'); - return server.putVersion(PKG_GH131, '0.0.1', pkg) + return server + .putVersion(PKG_GH131, '0.0.1', pkg) .status(HTTP_STATUS.CREATED) .body_ok(/published/); }); @@ -51,8 +51,7 @@ export default function (server, server2, server3) { }); beforeAll(function () { - return server3.getTarball(PKG_GH131, TARBALL) - .status(HTTP_STATUS.OK); + return server3.getTarball(PKG_GH131, TARBALL).status(HTTP_STATUS.OK); }); test('should be caching packages from uplink server1', () => { @@ -64,7 +63,8 @@ export default function (server, server2, server3) { }); beforeAll(function () { - return server2.putTarball(PKG_GH1312, TARBALL, getBinary()) + return server2 + .putTarball(PKG_GH1312, TARBALL, getBinary()) .status(HTTP_STATUS.CREATED) .body_ok(/.*/); }); @@ -73,24 +73,22 @@ export default function (server, server2, server3) { const pkg = requirePackage(PKG_GH1312); pkg.dist.shasum = createTarballHash().update(getBinary()).digest('hex'); - return server2.putVersion(PKG_GH1312, '0.0.1', pkg) + return server2 + .putVersion(PKG_GH1312, '0.0.1', pkg) .status(HTTP_STATUS.CREATED) .body_ok(/published/); }); beforeAll(function () { - return server3.getPackage(PKG_GH1312) - .status(HTTP_STATUS.OK); + return server3.getPackage(PKG_GH1312).status(HTTP_STATUS.OK); }); beforeAll(function () { - return server3.getTarball(PKG_GH1312, TARBALL) - .status(HTTP_STATUS.OK); + return server3.getTarball(PKG_GH1312, TARBALL).status(HTTP_STATUS.OK); }); test('must not be caching packages from uplink server2', () => { expect(isCached(PKG_GH1312, TARBALL)).toEqual(false); }); - }); } diff --git a/test/functional/uplinks/timeout.ts b/test/functional/uplinks/timeout.ts index 0e0f4fbce..c894d9f80 100644 --- a/test/functional/uplinks/timeout.ts +++ b/test/functional/uplinks/timeout.ts @@ -1,12 +1,10 @@ -import {HTTP_STATUS} from "../../../src/lib/constants"; +import { HTTP_STATUS } from '../../../src/lib/constants'; const PKG_SINGLE_UPLINK = 'test-uplink-timeout-single'; const PKG_MULTIPLE_UPLINKS = 'test-uplink-timeout-multiple'; export default function (server, server2, server3) { - describe('uplink connection timeouts', () => { - // more info: https://github.com/verdaccio/verdaccio/pull/1331 jest.setTimeout(20000); @@ -22,10 +20,8 @@ export default function (server, server2, server3) { }); test('200 response even though one uplink timeout', () => { - return server.getPackage(PKG_MULTIPLE_UPLINKS).status(HTTP_STATUS.OK) + return server.getPackage(PKG_MULTIPLE_UPLINKS).status(HTTP_STATUS.OK); }); }); - }); - } diff --git a/test/lib/request.ts b/test/lib/request.ts index ae3c58432..6340f68d4 100644 --- a/test/lib/request.ts +++ b/test/lib/request.ts @@ -5,8 +5,7 @@ import { IRequestPromise } from '../types'; const requestData = Symbol('smart_request_data'); -export class PromiseAssert extends Promise implements IRequestPromise{ - +export class PromiseAssert extends Promise implements IRequestPromise { public constructor(options: any) { super(options); } @@ -14,56 +13,64 @@ export class PromiseAssert extends Promise implements IRequestPromise{ public status(expected: number) { const selfData = this[requestData]; - return injectResponse(this, this.then(function(body) { - try { - assert.equal(selfData.response.statusCode, expected); - } catch(err) { - selfData.error.message = err.message; - throw selfData.error; - } - return body; - })); + return injectResponse( + this, + this.then(function (body) { + try { + assert.equal(selfData.response.statusCode, expected); + } catch (err) { + selfData.error.message = err.message; + throw selfData.error; + } + return body; + }) + ); } public body_ok(expected: any) { const selfData = this[requestData]; - return injectResponse(this, this.then(function(body) { - try { - if (_.isRegExp(expected)) { - assert(body.ok.match(expected), '\'' + body.ok + '\' doesn\'t match ' + expected); - } else { - assert.equal(body.ok, expected); + return injectResponse( + this, + this.then(function (body) { + try { + if (_.isRegExp(expected)) { + assert(body.ok.match(expected), "'" + body.ok + "' doesn't match " + expected); + } else { + assert.equal(body.ok, expected); + } + assert.equal(body.error, null); + } catch (err) { + selfData.error.message = err.message; + throw selfData.error; } - assert.equal(body.error, null); - } catch(err) { - selfData.error.message = err.message; - throw selfData.error; - } - return body; - })); + return body; + }) + ); } - public body_error(expected: any) { // $FlowFixMe const selfData = this[requestData]; - return injectResponse(this, this.then(function(body) { - try { - if (_.isRegExp(expected)) { - assert(body.error.match(expected), body.error + ' doesn\'t match ' + expected); - } else { - assert.equal(body.error, expected); + return injectResponse( + this, + this.then(function (body) { + try { + if (_.isRegExp(expected)) { + assert(body.error.match(expected), body.error + " doesn't match " + expected); + } else { + assert.equal(body.error, expected); + } + assert.equal(body.ok, null); + } catch (err) { + selfData.error.message = err.message; + throw selfData.error; } - assert.equal(body.ok, null); - } catch(err) { - selfData.error.message = err.message; - throw selfData.error; - } - return body; - })); + return body; + }) + ); } public request(callback: any) { @@ -74,17 +81,19 @@ export class PromiseAssert extends Promise implements IRequestPromise{ public response(cb: any) { const selfData = this[requestData]; - return injectResponse(this, this.then(function(body) { - cb(selfData.response); - return body; - })); + return injectResponse( + this, + this.then(function (body) { + cb(selfData.response); + return body; + }) + ); } public send(data: any) { this[requestData].request.end(data); return this; } - } function injectResponse(smartObject: any, promise: Promise): Promise { @@ -93,7 +102,6 @@ function injectResponse(smartObject: any, promise: Promise): Promise { return promise; } - function smartRequest(options: any): Promise { const smartObject: any = {}; @@ -101,9 +109,9 @@ function smartRequest(options: any): Promise { smartObject[requestData].error = Error(); Error.captureStackTrace(smartObject[requestData].error, smartRequest); - const promiseResult: Promise = new PromiseAssert(function(resolve, reject) { + const promiseResult: Promise = new PromiseAssert(function (resolve, reject) { // store request reference on symbol - smartObject[requestData].request = request(options, function(err, res, body) { + smartObject[requestData].request = request(options, function (err, res, body) { if (err) { return reject(err); } @@ -118,4 +126,3 @@ function smartRequest(options: any): Promise { } export default smartRequest; - diff --git a/test/lib/server.ts b/test/lib/server.ts index c1174e3c3..233810820 100644 --- a/test/lib/server.ts +++ b/test/lib/server.ts @@ -1,10 +1,10 @@ import _ from 'lodash'; import assert from 'assert'; import smartRequest from './request'; -import {IServerBridge} from '../types'; -import {API_MESSAGE, HEADERS, HTTP_STATUS, TOKEN_BASIC} from '../../src/lib/constants'; -import {buildToken} from "../../src/lib/utils"; -import {CREDENTIALS} from "../functional/config.functional"; +import { IServerBridge } from '../types'; +import { API_MESSAGE, HEADERS, HTTP_STATUS, TOKEN_BASIC } from '../../src/lib/constants'; +import { buildToken } from '../../src/lib/utils'; +import { CREDENTIALS } from '../functional/config.functional'; import getPackage from '../functional/fixtures/package'; const buildAuthHeader = (user, pass): string => { @@ -35,7 +35,7 @@ export default class Server implements IServerBridge { method: options.method || 'GET', headers: headers, encoding: options.encoding, - json: _.isNil(options.json) === false ? options.json : true, + json: _.isNil(options.json) === false ? options.json : true }); } @@ -51,23 +51,22 @@ export default class Server implements IServerBridge { _id: `org.couchdb.user:${name}`, type: 'user', roles: [], - date: new Date(), - }, + date: new Date() + } }); } public logout(token: string) { return this.request({ uri: `/-/user/token/${encodeURIComponent(token)}`, - method: 'DELETE', + method: 'DELETE' }); } - public getPackage(name: string) { return this.request({ uri: `/${encodeURIComponent(name)}`, - method: 'GET', + method: 'GET' }); } @@ -80,8 +79,8 @@ export default class Server implements IServerBridge { uri: `/${encodeURIComponent(name)}`, method: 'PUT', headers: { - [HEADERS.CONTENT_TYPE]: HEADERS.JSON, - }, + [HEADERS.CONTENT_TYPE]: HEADERS.JSON + } }).send(data); } @@ -94,8 +93,8 @@ export default class Server implements IServerBridge { uri: `/${encodeURIComponent(name)}/${encodeURIComponent(version)}/-tag/latest`, method: 'PUT', headers: { - [HEADERS.CONTENT_TYPE]: HEADERS.JSON, - }, + [HEADERS.CONTENT_TYPE]: HEADERS.JSON + } }).send(data); } @@ -103,7 +102,7 @@ export default class Server implements IServerBridge { return this.request({ uri: `/${encodeURIComponent(name)}/-/${encodeURIComponent(filename)}`, method: 'GET', - encoding: null, + encoding: null }); } @@ -112,8 +111,8 @@ export default class Server implements IServerBridge { uri: `/${encodeURIComponent(name)}/-/${encodeURIComponent(filename)}/whatever`, method: 'PUT', headers: { - [HEADERS.CONTENT_TYPE]: HEADERS.OCTET_STREAM, - }, + [HEADERS.CONTENT_TYPE]: HEADERS.OCTET_STREAM + } }).send(data); } @@ -122,8 +121,8 @@ export default class Server implements IServerBridge { uri: `/${encodeURIComponent(name)}/-rev/whatever`, method: 'DELETE', headers: { - [HEADERS.CONTENT_TYPE]: HEADERS.JSON_CHARSET, - }, + [HEADERS.CONTENT_TYPE]: HEADERS.JSON_CHARSET + } }); } @@ -132,47 +131,51 @@ export default class Server implements IServerBridge { uri: `/${encodeURIComponent(name)}/-/${filename}/-rev/whatever`, method: 'DELETE', headers: { - [HEADERS.CONTENT_TYPE]: HEADERS.JSON_CHARSET, - }, + [HEADERS.CONTENT_TYPE]: HEADERS.JSON_CHARSET + } }); } - public addTag(name: string, tag: string, version: string) { return this.request({ uri: `/${encodeURIComponent(name)}/${encodeURIComponent(tag)}`, method: 'PUT', headers: { - [HEADERS.CONTENT_TYPE]: HEADERS.JSON, - }, + [HEADERS.CONTENT_TYPE]: HEADERS.JSON + } }).send(JSON.stringify(version)); } - public putTarballIncomplete(pkgName: string, filename: string, data: any, headerContentSize: number): Promise { + public putTarballIncomplete( + pkgName: string, + filename: string, + data: any, + headerContentSize: number + ): Promise { let promise = this.request({ uri: `/${encodeURIComponent(pkgName)}/-/${encodeURIComponent(filename)}/whatever`, method: 'PUT', headers: { [HEADERS.CONTENT_TYPE]: HEADERS.OCTET_STREAM, - [HEADERS.CONTENT_LENGTH]: headerContentSize, + [HEADERS.CONTENT_LENGTH]: headerContentSize }, - timeout: 1000, + timeout: 1000 }); - promise.request(function(req) { + promise.request(function (req) { req.write(data); // it auto abort the request - setTimeout(function() { + setTimeout(function () { req.req.abort(); }, 20); }); - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { promise - .then(function() { + .then(function () { reject(Error('no error')); }) - .catch(function(err) { + .catch(function (err) { if (err.code === 'ECONNRESET') { resolve(); } else { @@ -191,8 +194,9 @@ export default class Server implements IServerBridge { public whoami() { return this.request({ uri: '/-/whoami' - }).status(HTTP_STATUS.OK) - .then(function(body) { + }) + .status(HTTP_STATUS.OK) + .then(function (body) { return body.username; }); } @@ -200,8 +204,9 @@ export default class Server implements IServerBridge { public ping() { return this.request({ uri: '/-/ping' - }).status(HTTP_STATUS.OK) - .then(function(body) { + }) + .status(HTTP_STATUS.OK) + .then(function (body) { return body; }); } @@ -211,8 +216,8 @@ export default class Server implements IServerBridge { uri: '/-/_debug', method: 'GET', headers: { - [HEADERS.CONTENT_TYPE]: HEADERS.JSON, - }, - }) + [HEADERS.CONTENT_TYPE]: HEADERS.JSON + } + }); } } diff --git a/test/lib/server_process.ts b/test/lib/server_process.ts index 6e264558b..c064085b7 100644 --- a/test/lib/server_process.ts +++ b/test/lib/server_process.ts @@ -1,13 +1,12 @@ import _ from 'lodash'; import rimRaf from 'rimraf'; import path from 'path'; -import {fork} from 'child_process'; -import {CREDENTIALS} from '../functional/config.functional'; -import {HTTP_STATUS} from '../../src/lib/constants'; -import {IVerdaccioConfig, IServerBridge, IServerProcess} from '../types'; +import { fork } from 'child_process'; +import { CREDENTIALS } from '../functional/config.functional'; +import { HTTP_STATUS } from '../../src/lib/constants'; +import { IVerdaccioConfig, IServerBridge, IServerProcess } from '../types'; export default class VerdaccioProcess implements IServerProcess { - private bridge: IServerBridge; private config: IVerdaccioConfig; private childFork: any; @@ -15,11 +14,13 @@ export default class VerdaccioProcess implements IServerProcess { private silence: boolean; private cleanStore: boolean; - public constructor(config: IVerdaccioConfig, + public constructor( + config: IVerdaccioConfig, bridge: IServerBridge, silence = true, isDebug = false, - cleanStore = true) { + cleanStore = true + ) { this.config = config; this.bridge = bridge; this.silence = silence; @@ -29,7 +30,7 @@ export default class VerdaccioProcess implements IServerProcess { public init(verdaccioPath = '../../bin/verdaccio'): Promise { return new Promise((resolve, reject) => { - if(this.cleanStore) { + if (this.cleanStore) { rimRaf(this.config.storagePath, (err) => { if (_.isNil(err) === false) { reject(err); @@ -58,18 +59,26 @@ export default class VerdaccioProcess implements IServerProcess { }); } - const {configPath, port} = this.config; - this.childFork = fork(verdaccioRegisterWrap, ['-c', configPath, '-l', port as string], childOptions); + const { configPath, port } = this.config; + this.childFork = fork( + verdaccioRegisterWrap, + ['-c', configPath, '-l', port as string], + childOptions + ); this.childFork.on('message', (msg) => { // verdaccio_started is a message that comes from verdaccio in debug mode that notify has been started if ('verdaccio_started' in msg) { - this.bridge.debug().status(HTTP_STATUS.OK).then((body) => { - this.bridge.auth(CREDENTIALS.user, CREDENTIALS.password) - .status(HTTP_STATUS.CREATED) - .body_ok(new RegExp(CREDENTIALS.user)) - .then(() => resolve([this, body.pid]), reject) - }, reject); + this.bridge + .debug() + .status(HTTP_STATUS.OK) + .then((body) => { + this.bridge + .auth(CREDENTIALS.user, CREDENTIALS.password) + .status(HTTP_STATUS.CREATED) + .body_ok(new RegExp(CREDENTIALS.user)) + .then(() => resolve([this, body.pid]), reject); + }, reject); } }); @@ -81,5 +90,4 @@ export default class VerdaccioProcess implements IServerProcess { public stop(): void { return this.childFork.kill('SIGINT'); } - } diff --git a/test/lib/utils-test.ts b/test/lib/utils-test.ts index bb532c223..831da540d 100644 --- a/test/lib/utils-test.ts +++ b/test/lib/utils-test.ts @@ -1,30 +1,32 @@ -import { Version } from "@verdaccio/types"; +import { Version } from '@verdaccio/types'; export function generateNewVersion( pkgName: string, version: string, - shashum = '238e7641e59508dc9c20eb4ad37a8aa57ab777b4'): Version { + shashum = '238e7641e59508dc9c20eb4ad37a8aa57ab777b4' +): Version { // $FlowFixMe return { - "name": pkgName, - "version": version, - "description": "", - "main": "index.js", - "dependencies": { - "test": "^1.4.1" + name: pkgName, + version: version, + description: '', + main: 'index.js', + dependencies: { + test: '^1.4.1' }, - "author": "", - "license": "ISC", - "readme": "ERROR: No README data found!", - "_id": `${pkgName}@${version}`, - "_npmVersion": "5.5.1", - "_npmUser": { - "name": "Foo" + author: '', + license: 'ISC', + readme: 'ERROR: No README data found!', + _id: `${pkgName}@${version}`, + _npmVersion: '5.5.1', + _npmUser: { + name: 'Foo' }, - "dist": { - "integrity": "sha512-zVEqt1JUCOPsash9q4wMkJEDPD+QCx95TRhQII+JnoS31uBUKoZxhzvvUJCcLVy2CQG4QdwXARU7dYWPnrwhGg==", - "shasum": shashum, - "tarball": `http:\/\/localhost:4873\/${pkgName}\/-\/${pkgName}-${version}.tgz` + dist: { + integrity: + 'sha512-zVEqt1JUCOPsash9q4wMkJEDPD+QCx95TRhQII+JnoS31uBUKoZxhzvvUJCcLVy2CQG4QdwXARU7dYWPnrwhGg==', + shasum: shashum, + tarball: `http:\/\/localhost:4873\/${pkgName}\/-\/${pkgName}-${version}.tgz` } - } + }; } diff --git a/test/lib/verdaccio-server.ts b/test/lib/verdaccio-server.ts index c4ea6e1ce..adad98fd8 100644 --- a/test/lib/verdaccio-server.ts +++ b/test/lib/verdaccio-server.ts @@ -1,7 +1,6 @@ -import {IVerdaccioConfig} from '../types'; +import { IVerdaccioConfig } from '../types'; export class VerdaccioConfig implements IVerdaccioConfig { - public storagePath: string; public configPath: string; public domainPath: string; diff --git a/test/types-test/plugins/auth/example.auth.plugin.ts b/test/types-test/plugins/auth/example.auth.plugin.ts index b846da6d3..3a62d0272 100644 --- a/test/types-test/plugins/auth/example.auth.plugin.ts +++ b/test/types-test/plugins/auth/example.auth.plugin.ts @@ -4,7 +4,14 @@ import Config from '../../../../src/lib/config'; import { logger } from '../../../../src/lib/logger'; import { Callback } from '@verdaccio/types'; -import { Config as AppConfig, PackageAccess, IPluginAuth, RemoteUser, Logger, PluginOptions } from '@verdaccio/types'; +import { + Config as AppConfig, + PackageAccess, + IPluginAuth, + RemoteUser, + Logger, + PluginOptions +} from '@verdaccio/types'; class ExampleAuthPlugin implements IPluginAuth<{}> { config: AppConfig; @@ -72,12 +79,12 @@ class ExampleAuthCustomPlugin implements IPluginAuth<{}> { const config1: AppConfig = new Config({ storage: './storage', - self_path: '/home/sotrage', + self_path: '/home/sotrage' }); const options: PluginOptions<{}> = { config: config1, - logger: logger.child(), + logger: logger.child() }; const auth = new ExampleAuthPlugin(config1, options); @@ -85,7 +92,7 @@ const authSub = new ExampleAuthCustomPlugin(config1, options); const remoteUser: RemoteUser = { groups: [], real_groups: [], - name: 'test', + name: 'test' }; auth.authenticate('user', 'pass', () => {}); diff --git a/test/types-test/plugins/middleware/example.middleware.plugin.ts b/test/types-test/plugins/middleware/example.middleware.plugin.ts index ef6106082..5f1312c3c 100644 --- a/test/types-test/plugins/middleware/example.middleware.plugin.ts +++ b/test/types-test/plugins/middleware/example.middleware.plugin.ts @@ -3,21 +3,22 @@ /* eslint-disable no-unused-vars */ import Config from '../../../../src/lib/config'; -import {generatePackageTemplate} from '../../../../src/lib/storage-utils'; -import {readFile} from '../../../functional/lib/test.utils'; +import { generatePackageTemplate } from '../../../../src/lib/storage-utils'; +import { readFile } from '../../../functional/lib/test.utils'; import { Package } from '@verdaccio/types'; -const readMetadata = (fileName: string): Package => JSON.parse(readFile(`../../unit/partials/${fileName}`).toString()) as Package; +const readMetadata = (fileName: string): Package => + JSON.parse(readFile(`../../unit/partials/${fileName}`).toString()) as Package; import { Config as AppConfig, IPluginMiddleware, IStorageManager, RemoteUser, - IBasicAuth, + IBasicAuth } from '@verdaccio/types'; import { IUploadTarball, IReadTarball } from '@verdaccio/streams'; -import { generateVersion } from "../../../unit/__helper/utils"; +import { generateVersion } from '../../../unit/__helper/utils'; export default class ExampleMiddlewarePlugin implements IPluginMiddleware<{}> { register_middlewares(app: any, auth: IBasicAuth<{}>, storage: IStorageManager<{}>): void { @@ -27,16 +28,16 @@ export default class ExampleMiddlewarePlugin implements IPluginMiddleware<{}> { name: 'test' }; auth.authenticate('user', 'password', () => {}); - auth.allow_access({packageName: 'packageName'}, remoteUser, () => {}); + auth.allow_access({ packageName: 'packageName' }, remoteUser, () => {}); auth.add_user('user', 'password', () => {}); auth.aesEncrypt(Buffer.from('pass')); // storage storage.addPackage('name', generatePackageTemplate('test'), () => {}); storage.addVersion('name', 'version', generateVersion('name', '1.0.0'), 'tag', () => {}); - storage.mergeTags('name', {'latest': '1.0.0'}, () => {}); + storage.mergeTags('name', { latest: '1.0.0' }, () => {}); storage.changePackage('name', readMetadata('metadata'), 'revision', () => {}); storage.removePackage('name', () => {}); - storage.mergeTags('name', {'latest': '1.0.0'}, () => {}); + storage.mergeTags('name', { latest: '1.0.0' }, () => {}); storage.removeTarball('name', 'filename', 'revision', () => {}); const config1: AppConfig = new Config({ storage: './storage', @@ -48,4 +49,3 @@ export default class ExampleMiddlewarePlugin implements IPluginMiddleware<{}> { const search: IReadTarball = storage.search('test', {}); } } - diff --git a/test/types-test/plugins/storage/example.storage.plugin.ts b/test/types-test/plugins/storage/example.storage.plugin.ts index 768cb8f79..165035e31 100644 --- a/test/types-test/plugins/storage/example.storage.plugin.ts +++ b/test/types-test/plugins/storage/example.storage.plugin.ts @@ -7,19 +7,16 @@ import { Package, Token, TokenFilter, - IUploadTarball, IReadTarball + IUploadTarball, + IReadTarball } from '@verdaccio/types'; -import { - IPluginStorage, - IPackageStorageManager, - IPackageStorage -} from '@verdaccio/types'; -import { UploadTarball, ReadTarball} from '@verdaccio/streams'; +import { IPluginStorage, IPackageStorageManager, IPackageStorage } from '@verdaccio/types'; +import { UploadTarball, ReadTarball } from '@verdaccio/streams'; import Config from '../../../../src/lib/config'; -import {logger} from '../../../../src/lib/logger'; -import {generatePackageTemplate} from '../../../../src/lib/storage-utils'; +import { logger } from '../../../../src/lib/logger'; +import { generatePackageTemplate } from '../../../../src/lib/storage-utils'; class PackageStorage implements IPackageStorageManager { path: string; @@ -30,10 +27,13 @@ class PackageStorage implements IPackageStorageManager { this.logger = logger; } - updatePackage(name: string, updateHandler: Callback, + updatePackage( + name: string, + updateHandler: Callback, onWrite: Callback, transformPackage: Function, - onEnd: Callback) { + onEnd: Callback + ) { onEnd(); } @@ -58,7 +58,7 @@ class PackageStorage implements IPackageStorageManager { } writeTarball(name): IUploadTarball { - this.logger.debug({name}, 'some name @name'); + this.logger.debug({ name }, 'some name @name'); const uploadStream = new UploadTarball({}); uploadStream.on('close', () => {}); if (uploadStream.abort) { @@ -73,7 +73,7 @@ class PackageStorage implements IPackageStorageManager { } readTarball(name): IReadTarball { - this.logger.debug({name}, 'some name @name'); + this.logger.debug({ name }, 'some name @name'); const readTarballStream: IReadTarball = new ReadTarball({}); if (readTarballStream.abort) { @@ -94,9 +94,9 @@ class ExampleStoragePlugin implements IPluginStorage<{}> { } saveToken(token: Token): Promise { - return Promise.resolve(token) + return Promise.resolve(token); } - deleteToken(user: string, tokenKey: string): Promise{ + deleteToken(user: string, tokenKey: string): Promise { return Promise.resolve([user, tokenKey]); } @@ -107,7 +107,7 @@ class ExampleStoragePlugin implements IPluginStorage<{}> { token: '12321', // pragma: allowlist secret readonly: false, created: '123232' - } + }; return Promise.resolve([token, token]); } @@ -116,7 +116,8 @@ class ExampleStoragePlugin implements IPluginStorage<{}> { return Promise.resolve(); } - setSecret(secret: string): Promise { // pragma: allowlist secret + setSecret(secret: string): Promise { + // pragma: allowlist secret return Promise.resolve(secret); // pragma: allowlist secret } @@ -148,14 +149,17 @@ const config1: AppConfig = new Config({ self_path: '/home/sotrage' }); - const storage = new ExampleStoragePlugin(config1, logger.child()); storage.add('test', () => {}); storage.remove('test', () => {}); storage.getSecret().then(() => {}); storage.setSecret('newSecret').then(() => {}); -storage.search(() => {}, () => {}, 'validateName'); +storage.search( + () => {}, + () => {}, + 'validateName' +); storage.get(() => {}); const storageManager: IPackageStorage = storage.getPackageStorage('test'); @@ -164,7 +168,14 @@ if (storageManager) { storageManager.createPackage('test', generatePackageTemplate('test'), () => {}); storageManager.savePackage('fileName', generatePackageTemplate('test'), () => {}); // @ts-ignore - storageManager.updatePackage('pkgFileName', () => {}, () => {}, () => {}, () => {}); + storageManager.updatePackage( + 'pkgFileName', + () => {}, + () => {}, + // @ts-ignore + () => {}, + () => {} + ); storageManager.deletePackage('test', () => {}); storageManager.removePackage(() => {}); storageManager.readPackage('test', () => {}); diff --git a/test/types/index.ts b/test/types/index.ts index b17677c4b..9985e2726 100644 --- a/test/types/index.ts +++ b/test/types/index.ts @@ -19,6 +19,7 @@ export interface IServerProcess { stop(): void; } +// eslint-disable-next-line no-unused-vars declare class PromiseAssert extends Promise { public constructor(options: any); } @@ -39,7 +40,13 @@ export interface IServerBridge { removeTarball(name: string): Promise; removeSingleTarball(name: string, filename: string): Promise; addTag(name: string, tag: string, version: string): Promise; - putTarballIncomplete(name: string, filename: string, data: any, size: number, cb: Function): Promise; + putTarballIncomplete( + name: string, + filename: string, + data: any, + size: number, + cb: Function + ): Promise; addPackage(name: string): Promise; whoami(): Promise; ping(): Promise; diff --git a/test/unit/__helper/.eslintrc b/test/unit/__helper/.eslintrc new file mode 100644 index 000000000..8ec0114bb --- /dev/null +++ b/test/unit/__helper/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "max-len": "off" + } +} diff --git a/test/unit/__helper/api.ts b/test/unit/__helper/api.ts index 3598e8d92..31774151d 100644 --- a/test/unit/__helper/api.ts +++ b/test/unit/__helper/api.ts @@ -1,11 +1,11 @@ import _ from 'lodash'; import request from 'supertest'; -import {HEADER_TYPE, HEADERS, HTTP_STATUS, TOKEN_BEARER} from '../../../src/lib/constants'; -import {buildToken, encodeScopedUri} from '../../../src/lib/utils'; +import { HEADER_TYPE, HEADERS, HTTP_STATUS, TOKEN_BEARER } from '../../../src/lib/constants'; +import { buildToken, encodeScopedUri } from '../../../src/lib/utils'; import { Package } from '@verdaccio/types'; -import {getTaggedVersionFromPackage} from "./expects"; -import {generateRandomHexString} from "../../../src/lib/crypto-utils"; +import { getTaggedVersionFromPackage } from './expects'; +import { generateRandomHexString } from '../../../src/lib/crypto-utils'; // API Helpers @@ -19,42 +19,43 @@ export function putPackage( request: any, pkgName: string, publishMetadata: Package, - token?: string): Promise { - return new Promise((resolve) => { - let put = request.put(pkgName) - .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) - .send(JSON.stringify(publishMetadata)); - - if (_.isEmpty(token) === false ) { - expect(token).toBeDefined(); - put.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token as string)) - } - - put.set('accept', 'gzip') - .set('accept-encoding', HEADERS.JSON) - .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { - resolve([err, res]); - }); - }); -} - -export function deletePackage( - request: any, - pkgName: string, token?: string ): Promise { return new Promise((resolve) => { - let del = request.put(`/${encodeScopedUri(pkgName)}/-rev/${generateRandomHexString(8)}`) - .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON); + let put = request + .put(pkgName) + .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) + .send(JSON.stringify(publishMetadata)); - if (_.isNil(token) === false ) { - del.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token as string)) + if (_.isEmpty(token) === false) { + expect(token).toBeDefined(); + put.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token as string)); } - del.set('accept-encoding', HEADERS.JSON) + put + .set('accept', 'gzip') + .set('accept-encoding', HEADERS.JSON) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { + resolve([err, res]); + }); + }); +} + +export function deletePackage(request: any, pkgName: string, token?: string): Promise { + return new Promise((resolve) => { + let del = request + .put(`/${encodeScopedUri(pkgName)}/-rev/${generateRandomHexString(8)}`) + .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON); + + if (_.isNil(token) === false) { + del.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token as string)); + } + + del + .set('accept-encoding', HEADERS.JSON) + .expect(HTTP_STATUS.CREATED) + .end(function (err, res) { resolve([err, res]); }); }); @@ -64,7 +65,8 @@ export function getPackage( request: any, token: string, pkgName: string, - statusCode: number = HTTP_STATUS.OK): Promise { + statusCode: number = HTTP_STATUS.OK +): Promise { return new Promise((resolve) => { let getRequest = request.get(`/${pkgName}`); @@ -76,39 +78,47 @@ export function getPackage( getRequest .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(statusCode) - .end(function(err, res) { + .end(function (err, res) { resolve([err, res]); }); }); } -export function loginUserToken(request: any, - user: string, - credentials: any, - token: string, - statusCode: number = HTTP_STATUS.CREATED): Promise { +export function loginUserToken( + request: any, + user: string, + credentials: any, + token: string, + statusCode: number = HTTP_STATUS.CREATED +): Promise { // $FlowFixMe return new Promise((resolve) => { - request.put(`/-/user/org.couchdb.user:${user}`) + request + .put(`/-/user/org.couchdb.user:${user}`) .send(credentials) .set('authorization', buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(statusCode) - .end(function(err, res) { + .end(function (err, res) { return resolve([err, res]); }); }); } -export function addUser(request: any, user: string, credentials: any, - statusCode: number = HTTP_STATUS.CREATED): Promise { +export function addUser( + request: any, + user: string, + credentials: any, + statusCode: number = HTTP_STATUS.CREATED +): Promise { // $FlowFixMe return new Promise((resolve) => { - request.put(`/-/user/org.couchdb.user:${user}`) + request + .put(`/-/user/org.couchdb.user:${user}`) .send(credentials) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(statusCode) - .end(function(err, res) { + .end(function (err, res) { return resolve([err, res]); }); }); @@ -119,7 +129,7 @@ export async function getNewToken(request: any, credentials: any): Promise { const [err, res] = await addUser(request, credentials.name, credentials); expect(err).toBeNull(); - const {token, ok} = res.body; + const { token, ok } = res.body; expect(ok).toBeDefined(); expect(token).toBeDefined(); expect(typeof token).toBe('string'); @@ -127,36 +137,53 @@ export async function getNewToken(request: any, credentials: any): Promise { +export function getProfile( + request: any, + token: string, + statusCode: number = HTTP_STATUS.OK +): Promise { // $FlowFixMe return new Promise((resolve) => { - request.get(`/-/npm/v1/user`) + request + .get(`/-/npm/v1/user`) .set('authorization', buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(statusCode) - .end(function(err, res) { + .end(function (err, res) { return resolve([err, res]); }); }); } -export function postProfile(request: any, body: any, token: string, statusCode: number = HTTP_STATUS.OK): Promise { +export function postProfile( + request: any, + body: any, + token: string, + statusCode: number = HTTP_STATUS.OK +): Promise { // $FlowFixMe return new Promise((resolve) => { - request.post(`/-/npm/v1/user`) + request + .post(`/-/npm/v1/user`) .send(body) .set(HEADERS.AUTHORIZATION, `Bearer ${token}`) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(statusCode) - .end(function(err, res) { + .end(function (err, res) { return resolve([err, res]); }); }); } -export async function fetchPackageByVersionAndTag(app, encodedPkgName, pkgName, version, tag = 'latest') { +export async function fetchPackageByVersionAndTag( + app, + encodedPkgName, + pkgName, + version, + tag = 'latest' +) { // we retrieve the package to verify - const [err, resp]= await getPackage(request(app), '', encodedPkgName); + const [err, resp] = await getPackage(request(app), '', encodedPkgName); expect(err).toBeNull(); @@ -165,13 +192,18 @@ export async function fetchPackageByVersionAndTag(app, encodedPkgName, pkgName, } export async function isExistPackage(app, packageName) { - const [err]= await getPackage(request(app), '', encodeScopedUri(packageName), HTTP_STATUS.OK); + const [err] = await getPackage(request(app), '', encodeScopedUri(packageName), HTTP_STATUS.OK); return _.isNull(err); } export async function verifyPackageVersionDoesExist(app, packageName, version, token?: string) { - const [, res]= await getPackage(request(app), token as string, encodeScopedUri(packageName), HTTP_STATUS.OK); + const [, res] = await getPackage( + request(app), + token as string, + encodeScopedUri(packageName), + HTTP_STATUS.OK + ); const { versions } = res.body; const versionsKeys = Object.keys(versions); diff --git a/test/unit/__helper/expects.ts b/test/unit/__helper/expects.ts index dd975aaf2..350ea02d6 100644 --- a/test/unit/__helper/expects.ts +++ b/test/unit/__helper/expects.ts @@ -1,20 +1,19 @@ -import {DIST_TAGS, LATEST} from "../../../src/lib/constants"; - +import { DIST_TAGS, LATEST } from '../../../src/lib/constants'; /** * Verify whether the package tag match with the desired version. */ export function getTaggedVersionFromPackage(pkg, pkgName, tag: string = LATEST, version: string) { - // extract the tagged version - const taggedVersion = pkg[DIST_TAGS][tag]; - expect(taggedVersion).toBeDefined(); - expect(taggedVersion).toEqual(version); + // extract the tagged version + const taggedVersion = pkg[DIST_TAGS][tag]; + expect(taggedVersion).toBeDefined(); + expect(taggedVersion).toEqual(version); - // the version must exist - const latestPkg = pkg.versions[taggedVersion]; - expect(latestPkg).toBeDefined(); - // the name must match - expect(latestPkg.name).toEqual(pkgName); + // the version must exist + const latestPkg = pkg.versions[taggedVersion]; + expect(latestPkg).toBeDefined(); + // the name must match + expect(latestPkg.name).toEqual(pkgName); - return latestPkg; + return latestPkg; } diff --git a/test/unit/__helper/mock.ts b/test/unit/__helper/mock.ts index 5d879bd2d..705c72e90 100644 --- a/test/unit/__helper/mock.ts +++ b/test/unit/__helper/mock.ts @@ -1,9 +1,9 @@ import path from 'path'; -import {DOMAIN_SERVERS} from '../../functional/config.functional'; +import { DOMAIN_SERVERS } from '../../functional/config.functional'; import VerdaccioProcess from '../../lib/server_process'; -import {VerdaccioConfig} from '../../lib/verdaccio-server'; +import { VerdaccioConfig } from '../../lib/verdaccio-server'; import Server from '../../lib/server'; -import {IServerBridge} from '../../types'; +import { IServerBridge } from '../../types'; /** * Fork a Verdaccio process with a custom configuration. @@ -53,7 +53,12 @@ export function mockServer(port: number) { const storePath = path.join(pathStore, '/mock-store'); const configPath = path.join(pathStore, '/config-unit-mock-server-test.yaml'); - const verdaccioConfig = new VerdaccioConfig(storePath, configPath, `http://${DOMAIN_SERVERS}:${port}/`, port); + const verdaccioConfig = new VerdaccioConfig( + storePath, + configPath, + `http://${DOMAIN_SERVERS}:${port}/`, + port + ); const server: IServerBridge = new Server(verdaccioConfig.domainPath); diff --git a/test/unit/__helper/utils.ts b/test/unit/__helper/utils.ts index 5d567b60a..8504800dc 100644 --- a/test/unit/__helper/utils.ts +++ b/test/unit/__helper/utils.ts @@ -1,44 +1,46 @@ -import { Package } from "@verdaccio/types"; +import { Package } from '@verdaccio/types'; export function generateAttachment() { - return { - "content_type": "application\/octet-stream", - "data": "H4sIAAAAAAAAE+2W32vbMBDH85y\/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo\/\/79KPeQsnIw5KUDX\/9IOvurLuz\/DHSjK\/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1aW8eML+Vv10m9oF\/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0ScCdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI\/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yoEHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS\/pLQe+D+FIv\/agIWI6GX66kFuIhT+1gDjrp\/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0\/jWiAK8OcMjt8MW3OlfQppcuhhQ6k+2OgkK2Q8DssFPi\/IHpU9fz3\/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6\/f88f\/Pu47zomiPk2Lv\/dOv8h+P\/34\/D\/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=", - "length": 512 - } + return { + content_type: 'application/octet-stream', + data: + 'H4sIAAAAAAAAE+2W32vbMBDH85y/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo//79KPeQsnIw5KUDX/9IOvurLuz/DHSjK/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1aW8eML+Vv10m9oF/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0ScCdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yoEHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS/pLQe+D+FIv/agIWI6GX66kFuIhT+1gDjrp/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0/jWiAK8OcMjt8MW3OlfQppcuhhQ6k+2OgkK2Q8DssFPi/IHpU9fz3/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6/f88f/Pu47zomiPk2Lv/dOv8h+P/34/D/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=', + length: 512 + }; } export function generateVersion(pkgName, version) { - return { - "name": pkgName, - "version": version, - "description": "some foo dependency", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": { - "name": "User NPM", - "email": "user@domain.com" - }, - "license": "ISC", - "dependencies": { - "verdaccio": "^4.0.0" - }, - "readme": "# test", - "readmeFilename": "README.md", - "_id": `${pkgName}@${version}`, - "_npmVersion": "5.5.1", - "_npmUser": { - 'name': 'foo', - }, - "dist": { - "integrity": "sha512-6gHiERpiDgtb3hjqpQH5\/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==", - "shasum": "2c03764f651a9f016ca0b7620421457b619151b9", // pragma: allowlist secret - "tarball": `http:\/\/localhost:5555\/${pkgName}\/-\/${pkgName}-${version}.tgz` - } - } + return { + name: pkgName, + version: version, + description: 'some foo dependency', + main: 'index.js', + scripts: { + test: 'echo "Error: no test specified" && exit 1' + }, + keywords: [], + author: { + name: 'User NPM', + email: 'user@domain.com' + }, + license: 'ISC', + dependencies: { + verdaccio: '^4.0.0' + }, + readme: '# test', + readmeFilename: 'README.md', + _id: `${pkgName}@${version}`, + _npmVersion: '5.5.1', + _npmUser: { + name: 'foo' + }, + dist: { + integrity: + 'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==', + shasum: '2c03764f651a9f016ca0b7620421457b619151b9', // pragma: allowlist secret + tarball: `http:\/\/localhost:5555\/${pkgName}\/-\/${pkgName}-${version}.tgz` + } + }; } /** @@ -47,28 +49,28 @@ export function generateVersion(pkgName, version) { * if you intent to to generate a complete metadata include multiple versions. */ export function generatePackageBody(pkgName: string, _versions: string[] = ['1.0.0']): Package { - const latest: string = _versions[_versions.length - 1]; - const versions = _versions.reduce((cat, version) => { - cat[version] = generateVersion(pkgName, version); - return cat; - }, {}); + const latest: string = _versions[_versions.length - 1]; + const versions = _versions.reduce((cat, version) => { + cat[version] = generateVersion(pkgName, version); + return cat; + }, {}); - const attachtment = _versions.reduce((cat, version) => { - cat[`${pkgName}-${version}.tgz`] = generateAttachment(); - return cat; - }, {}); + const attachtment = _versions.reduce((cat, version) => { + cat[`${pkgName}-${version}.tgz`] = generateAttachment(); + return cat; + }, {}); - // @ts-ignore - return { - "_id": pkgName, - "name": pkgName, - "readme": "# test", - "dist-tags": { - "latest": latest - }, - "versions": versions, - "_attachments": attachtment - } + // @ts-ignore + return { + _id: pkgName, + name: pkgName, + readme: '# test', + 'dist-tags': { + latest: latest + }, + versions: versions, + _attachments: attachtment + }; } /** @@ -77,92 +79,99 @@ export function generatePackageBody(pkgName: string, _versions: string[] = ['1.0 * @param pkgName * @param _versions */ -export function generatePackageUnpublish(pkgName: string, _versions: string[] = ['1.0.0']): Package { - const latest: string = _versions[_versions.length - 1]; - const versions = _versions.reduce((cat, version) => { - cat[version] = generateVersion(pkgName, version); - return cat; - }, {}); +export function generatePackageUnpublish( + pkgName: string, + _versions: string[] = ['1.0.0'] +): Package { + const latest: string = _versions[_versions.length - 1]; + const versions = _versions.reduce((cat, version) => { + cat[version] = generateVersion(pkgName, version); + return cat; + }, {}); - // @ts-ignore - return { - "_id": pkgName, - "name": pkgName, - "readme": "# test", - // users usually is present when run npm star [pkg] - "users": {}, - "dist-tags": { - "latest": latest - }, - "versions": versions, - } + // @ts-ignore + return { + _id: pkgName, + name: pkgName, + readme: '# test', + // users usually is present when run npm star [pkg] + users: {}, + 'dist-tags': { + latest: latest + }, + versions: versions + }; } export function generateStarMedatada(pkgName: string, users): any { - return { - "_id": pkgName, - "_rev": "3-b0cdaefc9bdb77c8", - "users": users - } + return { + _id: pkgName, + _rev: '3-b0cdaefc9bdb77c8', + users: users + }; } export function generatePackageMetadata(pkgName: string, version = '1.0.0'): Package { - // @ts-ignore - return { - "_id": pkgName, - "name": pkgName, - "dist-tags": { - "latest": version - }, - "versions": { - [version]: { - "name": pkgName, - "version": version, - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [ - - ], - "author": { - "name": "User NPM", - "email": "user@domain.com" - }, - "license": "ISC", - "dependencies": { - "verdaccio": "^2.7.2" - }, - "readme": "# test", - "readmeFilename": "README.md", - "_id": `${pkgName}@${version}`, - "_npmVersion": "5.5.1", - "_npmUser": { - 'name': 'foo', - }, - "dist": { - "integrity": "sha512-6gHiERpiDgtb3hjqpQH5\/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==", - "shasum": "2c03764f651a9f016ca0b7620421457b619151b9", // pragma: allowlist secret - "tarball": `http:\/\/localhost:5555\/${pkgName}\/-\/${pkgName}-${version}.tgz` - } - } - }, - "readme": "# test", - "_attachments": { - [`${pkgName}-${version}.tgz`]: { - "content_type": "application\/octet-stream", - "data": "H4sIAAAAAAAAE+2W32vbMBDH85y\/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo\/\/79KPeQsnIw5KUDX\/9IOvurLuz\/DHSjK\/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1aW8eML+Vv10m9oF\/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0ScCdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI\/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yoEHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS\/pLQe+D+FIv\/agIWI6GX66kFuIhT+1gDjrp\/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0\/jWiAK8OcMjt8MW3OlfQppcuhhQ6k+2OgkK2Q8DssFPi\/IHpU9fz3\/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6\/f88f\/Pu47zomiPk2Lv\/dOv8h+P\/34\/D\/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=", - "length": 512 - } - } - } + // @ts-ignore + return { + _id: pkgName, + name: pkgName, + 'dist-tags': { + latest: version + }, + versions: { + [version]: { + name: pkgName, + version: version, + description: '', + main: 'index.js', + scripts: { + test: 'echo "Error: no test specified" && exit 1' + }, + keywords: [], + author: { + name: 'User NPM', + email: 'user@domain.com' + }, + license: 'ISC', + dependencies: { + verdaccio: '^2.7.2' + }, + readme: '# test', + readmeFilename: 'README.md', + _id: `${pkgName}@${version}`, + _npmVersion: '5.5.1', + _npmUser: { + name: 'foo' + }, + dist: { + integrity: + 'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==', + shasum: '2c03764f651a9f016ca0b7620421457b619151b9', // pragma: allowlist secret + tarball: `http:\/\/localhost:5555\/${pkgName}\/-\/${pkgName}-${version}.tgz` + } + } + }, + readme: '# test', + _attachments: { + [`${pkgName}-${version}.tgz`]: { + content_type: 'application/octet-stream', + data: + 'H4sIAAAAAAAAE+2W32vbMBDH85y/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo//79KPeQsnIw5KUDX/9IOvurLuz/DHSjK/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1aW8eML+Vv10m9oF/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0ScCdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yoEHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS/pLQe+D+FIv/agIWI6GX66kFuIhT+1gDjrp/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0/jWiAK8OcMjt8MW3OlfQppcuhhQ6k+2OgkK2Q8DssFPi/IHpU9fz3/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6/f88f/Pu47zomiPk2Lv/dOv8h+P/34/D/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=', + length: 512 + } + } + }; } -export function generateDeprecateMetadata(pkgName: string, version = '1.0.0', deprecated:string = ''): Package { +export function generateDeprecateMetadata( + pkgName: string, + version = '1.0.0', + deprecated: string = '' +): Package { const res = { ...generatePackageMetadata(pkgName, version), - _attachments: {}, + _attachments: {} }; res.versions[version].deprecated = deprecated; return res; diff --git a/test/unit/functionalLibs/request.spec.ts b/test/unit/functionalLibs/request.spec.ts index 2b4b1f8d2..f05878a6f 100644 --- a/test/unit/functionalLibs/request.spec.ts +++ b/test/unit/functionalLibs/request.spec.ts @@ -1,7 +1,7 @@ import _ from 'lodash'; -import smartRequest, {PromiseAssert} from '../../lib/request'; -import {mockServer} from '../__helper/mock'; -import {HTTP_STATUS} from '../../../src/lib/constants'; +import smartRequest, { PromiseAssert } from '../../lib/request'; +import { mockServer } from '../__helper/mock'; +import { HTTP_STATUS } from '../../../src/lib/constants'; import { IRequestPromise } from '../../types'; import { VerdaccioError } from '@verdaccio/commons-api'; @@ -17,7 +17,7 @@ describe('Request Functional', () => { }); test('basic resolve', (done) => { - const requestPromise: IRequestPromise = new PromiseAssert(resolve => { + const requestPromise: IRequestPromise = new PromiseAssert((resolve) => { resolve(1); }); // @ts-ignore @@ -28,12 +28,11 @@ describe('Request Functional', () => { }); }); describe('smartRequest Rest', () => { - beforeAll(async () => { mockRegistry = await mockServer(mockServerPort).init(); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); @@ -44,24 +43,26 @@ describe('Request Functional', () => { method: 'GET' }; - smartRequest(options).then((result)=> { + smartRequest(options).then((result) => { expect(_.isString(result)).toBeTruthy(); done(); - }) + }); }); describe('smartRequest Status', () => { - test('basic check status 200', (done) => { const options: any = { url: restTest, method: 'GET' }; // @ts-ignore - smartRequest(options).status(HTTP_STATUS.OK).then((result)=> { - expect(JSON.parse(result).name).toBe('jquery'); - done(); - }) + smartRequest(options) + // @ts-ignore + .status(HTTP_STATUS.OK) + .then((result) => { + expect(JSON.parse(result).name).toBe('jquery'); + done(); + }); }); test('basic check status 404', (done) => { @@ -70,12 +71,18 @@ describe('Request Functional', () => { method: 'GET' }; // @ts-ignore - smartRequest(options).status(HTTP_STATUS.NOT_FOUND).then(() => { - // we do not intent to resolve this - }, (error: VerdaccioError) => { - expect(error.code).toBe('ENOTFOUND'); - done(); - }) + smartRequest(options) + // @ts-ignore + .status(HTTP_STATUS.NOT_FOUND) + .then( + () => { + // we do not intent to resolve this + }, + (error: VerdaccioError) => { + expect(error.code).toBe('ENOTFOUND'); + done(); + } + ); }); }); }); diff --git a/test/unit/modules/access/pkg.access.spec.ts b/test/unit/modules/access/pkg.access.spec.ts index b60fe98ee..126f5d76f 100644 --- a/test/unit/modules/access/pkg.access.spec.ts +++ b/test/unit/modules/access/pkg.access.spec.ts @@ -9,8 +9,8 @@ setup([]); import { HEADERS, HTTP_STATUS } from '../../../../src/lib/constants'; import configDefault from '../../partials/config'; import endPointAPI from '../../../../src/api'; -import {mockServer} from '../../__helper/mock'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; +import { mockServer } from '../../__helper/mock'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; require('../../../../src/lib/logger').setup([]); @@ -20,26 +20,27 @@ describe('api with no limited access configuration', () => { const store = path.join(__dirname, '../../partials/store/access-storage'); jest.setTimeout(10000); - beforeAll(function(done) { + beforeAll(function (done) { const mockServerPort = 55530; rimraf(store, async () => { - const configForTest = configDefault({ - auth: { - htpasswd: { - file: './access-storage/htpasswd-pkg-access' - } + const configForTest = configDefault( + { + auth: { + htpasswd: { + file: './access-storage/htpasswd-pkg-access' + } + }, + self_path: store, + uplinks: { + remote: { + url: `http://${DOMAIN_SERVERS}:${mockServerPort}` + } + }, + logs: [{ type: 'stdout', format: 'pretty', level: 'warn' }] }, - self_path: store, - uplinks: { - remote: { - url: `http://${DOMAIN_SERVERS}:${mockServerPort}` - } - }, - logs: [ - { type: 'stdout', format: 'pretty', level: 'warn' } - ] - }, 'pkg.access.spec.yaml'); + 'pkg.access.spec.yaml' + ); app = await endPointAPI(configForTest); mockRegistry = await mockServer(mockServerPort).init(); @@ -47,7 +48,7 @@ describe('api with no limited access configuration', () => { }); }); - afterAll(function(done) { + afterAll(function (done) { rimraf(store, (err) => { if (err) { mockRegistry[0].stop(); @@ -60,16 +61,14 @@ describe('api with no limited access configuration', () => { }); describe('test proxy packages partially restricted', () => { - - test('should test fails on fetch endpoint /-/not-found', (done) => { request(app) - // @ts-ignore + // @ts-ignore .get('/not-found-for-sure') .set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADERS.CONTENT_TYPE, /json/) .expect(HTTP_STATUS.NOT_FOUND) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -85,7 +84,7 @@ describe('api with no limited access configuration', () => { .set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADERS.CONTENT_TYPE, /json/) .expect(HTTP_STATUS.OK) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -101,7 +100,7 @@ describe('api with no limited access configuration', () => { .set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADERS.CONTENT_TYPE, /json/) .expect(HTTP_STATUS.OK) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -110,5 +109,4 @@ describe('api with no limited access configuration', () => { }); }); }); - }); diff --git a/test/unit/modules/api/api.spec.ts b/test/unit/modules/api/api.spec.ts index f6001cc8d..3d5a21e7d 100644 --- a/test/unit/modules/api/api.spec.ts +++ b/test/unit/modules/api/api.spec.ts @@ -15,34 +15,33 @@ import { HTTP_STATUS, HEADER_TYPE, API_MESSAGE, - TOKEN_BEARER, + TOKEN_BEARER } from '../../../../src/lib/constants'; -import {mockServer} from '../../__helper/mock'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; -import {buildToken, encodeScopedUri} from '../../../../src/lib/utils'; +import { mockServer } from '../../__helper/mock'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; +import { buildToken, encodeScopedUri } from '../../../../src/lib/utils'; import { getNewToken, getPackage, putPackage, - verifyPackageVersionDoesExist, generateUnPublishURI + verifyPackageVersionDoesExist, + generateUnPublishURI } from '../../__helper/api'; import { generatePackageMetadata, generatePackageUnpublish, generateStarMedatada, generateDeprecateMetadata, - generateVersion, + generateVersion } from '../../__helper/utils'; const sleep = (delay) => { - return new Promise(resolve => { - setTimeout(resolve, delay) + return new Promise((resolve) => { + setTimeout(resolve, delay); }); -} +}; -require('../../../../src/lib/logger').setup([ - { type: 'stdout', format: 'pretty', level: 'warn' } -]); +require('../../../../src/lib/logger').setup([{ type: 'stdout', format: 'pretty', level: 'warn' }]); const credentials = { name: 'jota', password: 'secretPass' }; @@ -62,38 +61,39 @@ describe('endpoint unit test', () => { const mockServerPort = 55549; let mockRegistry; - beforeAll(function(done) { + beforeAll(function (done) { const store = path.join(__dirname, '../../partials/store/test-storage-api-spec'); rimraf(store, async () => { - const configForTest = configDefault({ - auth: { - htpasswd: { - file: './test-storage-api-spec/.htpasswd' - } - }, - filters: { - '../../modules/api/partials/plugin/filter': { - pkg: 'npm_test', - version: '2.0.0' - } - }, - storage: store, - self_path: store, - uplinks: { - npmjs: { - url: `http://${DOMAIN_SERVERS}:${mockServerPort}` + const configForTest = configDefault( + { + auth: { + htpasswd: { + file: './test-storage-api-spec/.htpasswd' + } }, - socketTimeout: { - url: `http://some.registry.timeout.com`, - max_fails: 2, - timeout: '1s', - fail_timeout: '1s' - } + filters: { + '../../modules/api/partials/plugin/filter': { + pkg: 'npm_test', + version: '2.0.0' + } + }, + storage: store, + self_path: store, + uplinks: { + npmjs: { + url: `http://${DOMAIN_SERVERS}:${mockServerPort}` + }, + socketTimeout: { + url: `http://some.registry.timeout.com`, + max_fails: 2, + timeout: '1s', + fail_timeout: '1s' + } + }, + logs: [{ type: 'stdout', format: 'pretty', level: 'warn' }] }, - logs: [ - { type: 'stdout', format: 'pretty', level: 'warn' } - ] - }, 'api.spec.yaml'); + 'api.spec.yaml' + ); app = await endPointAPI(configForTest); mockRegistry = await mockServer(mockServerPort).init(); @@ -101,24 +101,23 @@ describe('endpoint unit test', () => { }); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); afterEach(() => { nock.cleanAll(); - }) + }); describe('Registry API Endpoints', () => { - describe('should test ping api', () => { test('should test endpoint /-/ping', (done) => { request(app) .get('/-/ping') .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -129,18 +128,11 @@ describe('endpoint unit test', () => { describe('should test whoami api', () => { test('should test referer /whoami endpoint', (done) => { - request(app) - .get('/whoami') - .set('referer', 'whoami') - .expect(HTTP_STATUS.OK) - .end(done); + request(app).get('/whoami').set('referer', 'whoami').expect(HTTP_STATUS.OK).end(done); }); test('should test no referer /whoami endpoint', (done) => { - request(app) - .get('/whoami') - .expect(HTTP_STATUS.NOT_FOUND) - .end(done); + request(app).get('/whoami').expect(HTTP_STATUS.NOT_FOUND).end(done); }); test('should test /-/whoami endpoint', (done) => { @@ -148,7 +140,7 @@ describe('endpoint unit test', () => { .get('/-/whoami') .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -161,7 +153,7 @@ describe('endpoint unit test', () => { .get('/-/whoami') .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -171,7 +163,6 @@ describe('endpoint unit test', () => { }); describe('should test user api', () => { - describe('should test authorization headers with tokens only errors', () => { test('should fails on protected endpoint /-/auth-package bad format', (done) => { request(app) @@ -179,9 +170,11 @@ describe('endpoint unit test', () => { .set(HEADERS.AUTHORIZATION, 'FakeHader') .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .expect(HTTP_STATUS.FORBIDDEN) - .end(function(err, res) { + .end(function (err, res) { expect(res.body.error).toBeDefined(); - expect(res.body.error).toMatch(/authorization required to access package auth-package/); + expect(res.body.error).toMatch( + /authorization required to access package auth-package/ + ); done(); }); }); @@ -192,9 +185,11 @@ describe('endpoint unit test', () => { .set(HEADERS.AUTHORIZATION, TOKEN_BEARER) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .expect(HTTP_STATUS.FORBIDDEN) - .end(function(err, res) { + .end(function (err, res) { expect(res.body.error).toBeDefined(); - expect(res.body.error).toMatch(/authorization required to access package auth-package/); + expect(res.body.error).toMatch( + /authorization required to access package auth-package/ + ); done(); }); }); @@ -205,22 +200,23 @@ describe('endpoint unit test', () => { .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, '12345')) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .expect(HTTP_STATUS.FORBIDDEN) - .end(function(err, res) { + .end(function (err, res) { expect(res.body.error).toBeDefined(); - expect(res.body.error).toMatch(/authorization required to access package auth-package/); + expect(res.body.error).toMatch( + /authorization required to access package auth-package/ + ); done(); }); }); }); - test('should test add a new user', (done) => { request(app) .put(`/-/user/org.couchdb.user:${credentials.name}`) .send(credentials) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -237,7 +233,7 @@ describe('endpoint unit test', () => { .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { expect(err).toBeNull(); expect(res.body).toBeDefined(); expect(res.body.name).toMatch(/vue/); @@ -247,7 +243,6 @@ describe('endpoint unit test', () => { }); test('should test fails add a new user with missing name', (done) => { - const credentialsShort = _.cloneDeep(credentials); delete credentialsShort.name; @@ -256,7 +251,7 @@ describe('endpoint unit test', () => { .send(credentialsShort) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.BAD_REQUEST) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -268,7 +263,6 @@ describe('endpoint unit test', () => { }); test('should test fails add a new user with missing password', (done) => { - const credentialsShort = _.cloneDeep(credentials); delete credentialsShort.password; @@ -277,7 +271,7 @@ describe('endpoint unit test', () => { .send(credentialsShort) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.BAD_REQUEST) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -299,7 +293,7 @@ describe('endpoint unit test', () => { .send(newCredentials) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -314,7 +308,7 @@ describe('endpoint unit test', () => { .send(credentials) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.CONFLICT) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -325,7 +319,6 @@ describe('endpoint unit test', () => { }); test('should test fails add a new user with wrong password', (done) => { - const credentialsShort = _.cloneDeep(credentials); credentialsShort.password = 'failPassword'; @@ -334,7 +327,7 @@ describe('endpoint unit test', () => { .send(credentialsShort) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.UNAUTHORIZED) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -344,7 +337,6 @@ describe('endpoint unit test', () => { done(); }); }); - }); describe('should test package api', () => { @@ -356,13 +348,12 @@ describe('endpoint unit test', () => { // proxy: npmjs test('should fetch jquery package from remote uplink', (done) => { - request(app) .get('/jquery') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -377,18 +368,17 @@ describe('endpoint unit test', () => { const timeOutPkg = generatePackageMetadata('timeout', '1.5.1'); const responseText = 'fooooooooooooooooo'; const readable = Readable.from([responseText]); - timeOutPkg.versions['1.5.1'].dist.tarball = 'http://some.registry.timeout.com/timeout/-/timeout-1.5.1.tgz'; - nock('http://some.registry.timeout.com') - .get('/timeout') - .reply(200, timeOutPkg); + timeOutPkg.versions['1.5.1'].dist.tarball = + 'http://some.registry.timeout.com/timeout/-/timeout-1.5.1.tgz'; + nock('http://some.registry.timeout.com').get('/timeout').reply(200, timeOutPkg); nock('http://some.registry.timeout.com') .get('/timeout/-/timeout-1.5.1.tgz') .twice() .socketDelay(50000) - .reply(200); + .reply(200); nock('http://some.registry.timeout.com') - .get('/timeout/-/timeout-1.5.1.tgz') - .reply(200, () => readable); + .get('/timeout/-/timeout-1.5.1.tgz') + .reply(200, () => readable); const agent = request.agent(app); await agent .get('/timeout/-/timeout-1.5.1.tgz') @@ -407,13 +397,12 @@ describe('endpoint unit test', () => { }, 10000); test('should fetch jquery specific version package from remote uplink', (done) => { - request(app) .get('/jquery/1.5.1') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -425,13 +414,12 @@ describe('endpoint unit test', () => { }); test('should fetch jquery specific tag package from remote uplink', (done) => { - request(app) .get('/jquery/latest') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -443,13 +431,12 @@ describe('endpoint unit test', () => { }); test('should fails on fetch jquery specific tag package from remote uplink', (done) => { - request(app) .get('/jquery/never-will-exist-this-tag') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.NOT_FOUND) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -458,13 +445,12 @@ describe('endpoint unit test', () => { }); test('should not found a unexisting remote package under scope', (done) => { - request(app) .get('/@verdaccio/not-found') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.NOT_FOUND) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -479,7 +465,7 @@ describe('endpoint unit test', () => { .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -491,12 +477,12 @@ describe('endpoint unit test', () => { test('should not found when a filter fails', (done) => { request(app) - // Filter errors look like other uplink errors + // Filter errors look like other uplink errors .get('/trigger-filter-failure') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.NOT_FOUND) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -506,13 +492,12 @@ describe('endpoint unit test', () => { }); test('should forbid access to remote package', (done) => { - request(app) .get('/forbidden-place') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.UNAUTHORIZED) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -521,12 +506,11 @@ describe('endpoint unit test', () => { }); test('should fetch a tarball from remote uplink', (done) => { - request(app) .get('/jquery/-/jquery-1.5.1.tgz') .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.OCTET_STREAM) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -537,12 +521,11 @@ describe('endpoint unit test', () => { }); test('should fetch a scoped tarball from remote uplink', (done) => { - request(app) .get('/@jquery/jquery/-/@jquery/jquery-1.5.1.tgz') .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.OCTET_STREAM) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { return done(err); } @@ -553,12 +536,11 @@ describe('endpoint unit test', () => { }); test('should fails fetch a tarball from remote uplink', (done) => { - request(app) .get('/jquery/-/jquery-not-found-tarball-0.0.1.tgz') .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.OCTET_STREAM) .expect(HTTP_STATUS.NOT_FOUND) - .end(function(err) { + .end(function (err) { if (err) { expect(err).not.toBeNull(); return done(err); @@ -567,20 +549,19 @@ describe('endpoint unit test', () => { done(); }); }); - }); describe('should test dist-tag api', () => { const jqueryVersion = '2.1.2'; const jqueryUpdatedVersion = { - 'beta': '3.0.0', - 'jota': '1.6.3' + beta: '3.0.0', + jota: '1.6.3' }; test('should set a new tag on jquery', (done) => { putVersion(app, '/jquery/verdaccio-tag', jqueryVersion) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { if (err) { expect(err).toBeNull(); return done(err); @@ -593,13 +574,12 @@ describe('endpoint unit test', () => { }); test('should fetch all tag for jquery', (done) => { - request(app) .get('/-/package/jquery/dist-tags') .set('accept-encoding', HEADERS.JSON) .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { expect(err).toBeNull(); return done(err); @@ -612,13 +592,12 @@ describe('endpoint unit test', () => { }); test('should update a new tag on jquery', (done) => { - request(app) .post('/-/package/jquery/dist-tags') .send(JSON.stringify(jqueryUpdatedVersion)) .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { if (err) { expect(err).toBeNull(); return done(err); @@ -631,13 +610,12 @@ describe('endpoint unit test', () => { }); test('should fetch all tags for jquery and ccheck previous update', (done) => { - request(app) .get('/-/package/jquery/dist-tags') .set('accept-encoding', HEADERS.JSON) .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { if (err) { expect(err).toBeNull(); return done(err); @@ -650,14 +628,13 @@ describe('endpoint unit test', () => { }); test('should set a remove a tag on jquery', (done) => { - request(app) .del('/-/package/jquery/dist-tags/verdaccio-tag') .set('accept-encoding', HEADERS.JSON) .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) // .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { if (err) { expect(err).toBeNull(); return done(err); @@ -668,7 +645,6 @@ describe('endpoint unit test', () => { done(); }); }); - }); describe('should test search api', () => { @@ -681,7 +657,7 @@ describe('endpoint unit test', () => { // .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .expect(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err) { + .end(function (err) { if (err) { expect(err).toBeNull(); return done(err); @@ -691,7 +667,6 @@ describe('endpoint unit test', () => { done(); }); }); - }); describe('should test publish/unpublish api', () => { @@ -710,15 +685,24 @@ describe('endpoint unit test', () => { } const newVersion = '2.0.1'; - const [newErr] = await putPackage(request(app), `/${encodeScopedUri(pkgName)}`, - generatePackageMetadata(pkgName, newVersion), token); + const [newErr] = await putPackage( + request(app), + `/${encodeScopedUri(pkgName)}`, + generatePackageMetadata(pkgName, newVersion), + token + ); if (newErr) { expect(newErr).toBeNull(); return done(newErr); } - const deletePayload = generatePackageUnpublish(pkgName, ['2.0.0']); - const [err2, res2] = await putPackage(request(app), generateUnPublishURI(pkgName), deletePayload, token); + const deletePayload = generatePackageUnpublish(pkgName, ['2.0.0']); + const [err2, res2] = await putPackage( + request(app), + generateUnPublishURI(pkgName), + deletePayload, + token + ); expect(err2).toBeNull(); expect(res2.body.ok).toMatch(API_MESSAGE.PKG_CHANGED); @@ -767,18 +751,29 @@ describe('endpoint unit test', () => { const newVersion = '1.0.0'; const token = await getNewToken(request(app), credentials); - const [newErr] = await putPackage(request(app), `/${encodeScopedUri(pkgName)}`, - generatePackageMetadata(pkgName, newVersion), token); + const [newErr] = await putPackage( + request(app), + `/${encodeScopedUri(pkgName)}`, + generatePackageMetadata(pkgName, newVersion), + token + ); if (newErr) { expect(newErr).toBeNull(); return done(newErr); } - const deletePayload = generatePackageUnpublish(pkgName, ['2.0.0']); - const [err2, res2] = await putPackage(request(app), generateUnPublishURI(pkgName), deletePayload, token); + const deletePayload = generatePackageUnpublish(pkgName, ['2.0.0']); + const [err2, res2] = await putPackage( + request(app), + generateUnPublishURI(pkgName), + deletePayload, + token + ); expect(err2).not.toBeNull(); - expect(res2.body.error).toMatch(/user jota_unpublish_fail is not allowed to unpublish package non-unpublish/); + expect(res2.body.error).toMatch( + /user jota_unpublish_fail is not allowed to unpublish package non-unpublish/ + ); done(); }); @@ -804,11 +799,17 @@ describe('endpoint unit test', () => { const newVersion = '1.0.0'; const token = await getNewToken(request(app), credentials); - const [newErr, resp] = await putPackage(request(app), `/${encodeScopedUri(pkgName)}`, - generatePackageMetadata(pkgName, newVersion), token); + const [newErr, resp] = await putPackage( + request(app), + `/${encodeScopedUri(pkgName)}`, + generatePackageMetadata(pkgName, newVersion), + token + ); expect(newErr).not.toBeNull(); - expect(resp.body.error).toMatch(/user jota_only_unpublish_fail is not allowed to publish package only-unpublish/); + expect(resp.body.error).toMatch( + /user jota_only_unpublish_fail is not allowed to publish package only-unpublish/ + ); done(); }); }); @@ -820,11 +821,15 @@ describe('endpoint unit test', () => { .put('/super-admin-can-unpublish') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) - .send(JSON.stringify(_.assign({}, publishMetadata, { - name: 'super-admin-can-unpublish' - }))) + .send( + JSON.stringify( + _.assign({}, publishMetadata, { + name: 'super-admin-can-unpublish' + }) + ) + ) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { if (err) { expect(err).toBeNull(); return done(err); @@ -838,7 +843,7 @@ describe('endpoint unit test', () => { .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { expect(err).toBeNull(); expect(res.body.ok).toBeDefined(); expect(res.body.ok).toMatch(API_MESSAGE.PKG_REMOVED); @@ -854,11 +859,15 @@ describe('endpoint unit test', () => { .put('/all-can-unpublish') .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) - .send(JSON.stringify(_.assign({}, publishMetadata, { - name: 'all-can-unpublish' - }))) + .send( + JSON.stringify( + _.assign({}, publishMetadata, { + name: 'all-can-unpublish' + }) + ) + ) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { if (err) { expect(err).toBeNull(); return done(err); @@ -872,7 +881,7 @@ describe('endpoint unit test', () => { .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { expect(err).toBeNull(); expect(res.body.ok).toBeDefined(); expect(res.body.ok).toMatch(API_MESSAGE.PKG_REMOVED); @@ -883,93 +892,105 @@ describe('endpoint unit test', () => { }); describe('should test star and stars api', () => { - const pkgName = '@scope/starPackage'; - const credentials = { name: 'jota_star', password: 'secretPass' }; - let token = ''; - beforeAll(async (done) =>{ - token = await getNewToken(request(app), credentials); - await putPackage(request(app), `/${pkgName}`, generatePackageMetadata(pkgName), token); + const pkgName = '@scope/starPackage'; + const credentials = { name: 'jota_star', password: 'secretPass' }; + let token = ''; + beforeAll(async (done) => { + token = await getNewToken(request(app), credentials); + await putPackage(request(app), `/${pkgName}`, generatePackageMetadata(pkgName), token); + done(); + }); + + test('should star a package', (done) => { + request(app) + .put(`/${pkgName}`) + .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) + .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) + .send( + JSON.stringify( + generateStarMedatada(pkgName, { + [credentials.name]: true + }) + ) + ) + .expect(HTTP_STATUS.OK) + .end(function (err, res) { + if (err) { + expect(err).toBeNull(); + return done(err); + } + expect(res.body.success).toBeDefined(); + expect(res.body.success).toBeTruthy(); done(); - }); + }); + }); - test('should star a package', (done) => { - request(app) - .put(`/${pkgName}`) - .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) - .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) - .send(JSON.stringify(generateStarMedatada(pkgName, { - [credentials.name]: true - }))) - .expect(HTTP_STATUS.OK) - .end(function(err, res) { - if (err) { - expect(err).toBeNull(); - return done(err); - } - expect(res.body.success).toBeDefined(); - expect(res.body.success).toBeTruthy(); - done(); - }); - }); + test('should unstar a package', (done) => { + request(app) + .put(`/${pkgName}`) + .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) + .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) + .send(JSON.stringify(generateStarMedatada(pkgName, {}))) + .expect(HTTP_STATUS.OK) + .end(function (err, res) { + if (err) { + expect(err).toBeNull(); + return done(err); + } + expect(res.body.success).toBeDefined(); + expect(res.body.success).toBeTruthy(); + done(); + }); + }); - test('should unstar a package', (done) => { + test('should retrieve stars list with credentials', async (done) => { + request(app) + .put(`/${pkgName}`) + .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) + .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) + .send(generateStarMedatada(pkgName, { [credentials.name]: true })) + .expect(HTTP_STATUS.OK) + .end(function (err) { + if (err) { + expect(err).toBeNull(); + return done(err); + } request(app) - .put(`/${pkgName}`) - .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) - .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) - .send(JSON.stringify(generateStarMedatada(pkgName, {}))) - .expect(HTTP_STATUS.OK) - .end(function(err, res) { - if (err) { - expect(err).toBeNull(); - return done(err); - } - expect(res.body.success).toBeDefined(); - expect(res.body.success).toBeTruthy(); - done(); - }); - }); - - test('should retrieve stars list with credentials', async (done) => { - request(app) - .put(`/${pkgName}`) - .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) - .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) - .send(generateStarMedatada(pkgName, {[credentials.name]: true})) - .expect(HTTP_STATUS.OK).end(function(err) { + .get('/-/_view/starredByUser') + .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) + .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) + .send( + JSON.stringify({ + key: [credentials.name] + }) + ) + .expect(HTTP_STATUS.OK) + .end(function (err, res) { if (err) { - expect(err).toBeNull(); - return done(err); + expect(err).toBeNull(); + return done(err); } - request(app) - .get('/-/_view/starredByUser') - .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) - .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) - .send(JSON.stringify({ - key: [credentials.name] - })) - .expect(HTTP_STATUS.OK) - .end(function(err, res) { - if (err) { - expect(err).toBeNull(); - return done(err); - } - expect(res.body.rows).toBeDefined(); - expect(res.body.rows).toHaveLength(1); - done(); - }); - }); - }); + expect(res.body.rows).toBeDefined(); + expect(res.body.rows).toHaveLength(1); + done(); + }); + }); + }); }); describe('should test (un)deprecate api', () => { const pkgName = '@scope/deprecate'; const credentials = { name: 'jota_deprecate', password: 'secretPass' }; - const version = '1.0.0' + const version = '1.0.0'; let token = ''; - beforeAll(async (done) =>{ + beforeAll(async (done) => { token = await getNewToken(request(app), credentials); - await putPackage(request(app), `/${pkgName}`, generatePackageMetadata(pkgName, version), token); + await putPackage( + request(app), + `/${pkgName}`, + generatePackageMetadata(pkgName, version), + token + ); done(); }); @@ -980,7 +1001,7 @@ describe('endpoint unit test', () => { expect(err).toBeNull(); return done(err); } - const [,res] = await getPackage(request(app), '', pkgName); + const [, res] = await getPackage(request(app), '', pkgName); expect(res.body.versions[version].deprecated).toEqual('get deprecated'); done(); }); @@ -994,7 +1015,7 @@ describe('endpoint unit test', () => { expect(err).toBeNull(); return done(err); } - const [,res] = await getPackage(request(app), '', pkgName); + const [, res] = await getPackage(request(app), '', pkgName); expect(res.body.versions[version].deprecated).not.toBeDefined(); done(); }); @@ -1003,31 +1024,50 @@ describe('endpoint unit test', () => { let credentials = { name: 'only_publish', password: 'secretPass' }; let token = await getNewToken(request(app), credentials); const pkg = generateDeprecateMetadata(pkgName, version, 'get deprecated'); - const [err, res] = await putPackage(request(app), `/${encodeScopedUri(pkgName)}`, pkg, token); + const [err, res] = await putPackage( + request(app), + `/${encodeScopedUri(pkgName)}`, + pkg, + token + ); expect(err).not.toBeNull(); expect(res.body.error).toBeDefined(); - expect(res.body.error).toMatch(/user only_publish is not allowed to unpublish package @scope\/deprecate/); + expect(res.body.error).toMatch( + /user only_publish is not allowed to unpublish package @scope\/deprecate/ + ); credentials = { name: 'only_unpublish', password: 'secretPass' }; token = await getNewToken(request(app), credentials); - const [err2, res2] = await putPackage(request(app), `/${encodeScopedUri(pkgName)}`, pkg, token); + const [err2, res2] = await putPackage( + request(app), + `/${encodeScopedUri(pkgName)}`, + pkg, + token + ); expect(err2).not.toBeNull(); expect(res2.body.error).toBeDefined(); - expect(res2.body.error).toMatch(/user only_unpublish is not allowed to publish package @scope\/deprecate/); - }) + expect(res2.body.error).toMatch( + /user only_unpublish is not allowed to publish package @scope\/deprecate/ + ); + }); test('should deprecate multiple packages', async (done) => { - await putPackage(request(app), `/${pkgName}`, generatePackageMetadata(pkgName, '1.0.1'), token); + await putPackage( + request(app), + `/${pkgName}`, + generatePackageMetadata(pkgName, '1.0.1'), + token + ); const pkg = generateDeprecateMetadata(pkgName, version, 'get deprecated'); pkg.versions['1.0.1'] = { ...generateVersion(pkgName, '1.0.1'), - deprecated: 'get deprecated', + deprecated: 'get deprecated' }; await putPackage(request(app), `/${encodeScopedUri(pkgName)}`, pkg, token); - const [,res] = await getPackage(request(app), '', pkgName); + const [, res] = await getPackage(request(app), '', pkgName); expect(res.body.versions[version].deprecated).toEqual('get deprecated'); expect(res.body.versions['1.0.1'].deprecated).toEqual('get deprecated'); - done() - }) + done(); + }); }); }); }); diff --git a/test/unit/modules/api/partials/plugin/filter.ts b/test/unit/modules/api/partials/plugin/filter.ts index a3caa169c..b542d411c 100644 --- a/test/unit/modules/api/partials/plugin/filter.ts +++ b/test/unit/modules/api/partials/plugin/filter.ts @@ -7,7 +7,7 @@ class FilterPlugin { public filter_metadata(pkg) { return new Promise((resolve, reject) => { // We use this to test what happens when a filter rejects - if(pkg.name === 'trigger-filter-failure') { + if (pkg.name === 'trigger-filter-failure') { reject(new Error('Example filter failure')); return; } @@ -17,8 +17,7 @@ class FilterPlugin { delete pkg.versions[this._config.version]; } resolve(pkg); - } - ); + }); } } diff --git a/test/unit/modules/api/publish.spec.ts b/test/unit/modules/api/publish.spec.ts index 2bad6835e..58c1e6236 100644 --- a/test/unit/modules/api/publish.spec.ts +++ b/test/unit/modules/api/publish.spec.ts @@ -1,11 +1,15 @@ -import { addVersion, uploadPackageTarball, removeTarball, unPublishPackage, publishPackage } from '../../../../src/api/endpoint/api/publish'; +import { + addVersion, + uploadPackageTarball, + removeTarball, + unPublishPackage, + publishPackage +} from '../../../../src/api/endpoint/api/publish'; import { HTTP_STATUS, API_ERROR } from '../../../../src/lib/constants'; const REVISION_MOCK = '15-e53a77096b0ee33e'; -require('../../../../src/lib/logger').setup([ - { type: 'stdout', format: 'pretty', level: 'info' } -]); +require('../../../../src/lib/logger').setup([{ type: 'stdout', format: 'pretty', level: 'info' }]); describe('Publish endpoints - add a tag', () => { let req; @@ -17,18 +21,18 @@ describe('Publish endpoints - add a tag', () => { params: { version: '1.0.0', tag: 'tag', - package: 'verdaccio', + package: 'verdaccio' }, - body: '', + body: '' }; res = { - status: jest.fn(), + status: jest.fn() }; next = jest.fn(); }); - test('should add a version', done => { + test('should add a version', (done) => { const storage = { addVersion: (packageName, version, body, tag, cb) => { expect(packageName).toEqual(req.params.package); @@ -37,7 +41,7 @@ describe('Publish endpoints - add a tag', () => { expect(tag).toEqual(req.params.tag); cb(); done(); - }, + } }; // @ts-ignore @@ -47,15 +51,15 @@ describe('Publish endpoints - add a tag', () => { expect(next).toHaveBeenLastCalledWith({ ok: 'package published' }); }); - test('when failed to add a version', done => { + test('when failed to add a version', (done) => { const storage = { addVersion: (packageName, version, body, tag, cb) => { const error = { - message: 'failure', + message: 'failure' }; cb(error); done(); - }, + } }; // @ts-ignore @@ -77,10 +81,10 @@ describe('Publish endpoints - upload package tarball', () => { req = { params: { filename: 'verdaccio.gzip', - package: 'verdaccio', + package: 'verdaccio' }, pipe: jest.fn(), - on: jest.fn(), + on: jest.fn() }; res = { status: jest.fn(), report_error: jest.fn() }; next = jest.fn(); @@ -90,14 +94,14 @@ describe('Publish endpoints - upload package tarball', () => { const stream = { done: jest.fn(), abort: jest.fn(), - on: jest.fn(() => (status, cb) => cb()), + on: jest.fn(() => (status, cb) => cb()) }; const storage = { addTarball(packageName, filename) { expect(packageName).toEqual(req.params.package); expect(filename).toEqual(req.params.filename); return stream; - }, + } }; // @ts-ignore @@ -120,14 +124,14 @@ describe('Publish endpoints - delete tarball', () => { params: { filename: 'verdaccio.gzip', package: 'verdaccio', - revision: REVISION_MOCK, - }, + revision: REVISION_MOCK + } }; res = { status: jest.fn() }; next = jest.fn(); }); - test('should delete tarball successfully', done => { + test('should delete tarball successfully', (done) => { const storage = { removeTarball(packageName, filename, revision, cb) { expect(packageName).toEqual(req.params.package); @@ -135,7 +139,7 @@ describe('Publish endpoints - delete tarball', () => { expect(revision).toEqual(req.params.revision); cb(); done(); - }, + } }; // @ts-ignore @@ -144,15 +148,15 @@ describe('Publish endpoints - delete tarball', () => { expect(next).toHaveBeenCalledWith({ ok: 'tarball removed' }); }); - test('failed while deleting the tarball', done => { + test('failed while deleting the tarball', (done) => { const error = { - message: 'deletion failed', + message: 'deletion failed' }; const storage = { removeTarball(packageName, filename, revision, cb) { cb(error); done(); - }, + } }; // @ts-ignore @@ -172,20 +176,20 @@ describe('Publish endpoints - un-publish package', () => { beforeEach(() => { req = { params: { - package: 'verdaccio', - }, + package: 'verdaccio' + } }; res = { status: jest.fn() }; next = jest.fn(); }); - test('should un-publish package successfully', done => { + test('should un-publish package successfully', (done) => { const storage = { removePackage(packageName, cb) { expect(packageName).toEqual(req.params.package); cb(); done(); - }, + } }; // @ts-ignore @@ -194,15 +198,15 @@ describe('Publish endpoints - un-publish package', () => { expect(next).toHaveBeenCalledWith({ ok: 'package removed' }); }); - test('un-publish failed', done => { + test('un-publish failed', (done) => { const error = { - message: 'un-publish failed', + message: 'un-publish failed' }; const storage = { removePackage(packageName, cb) { cb(error); done(); - }, + } }; // @ts-ignore @@ -222,11 +226,11 @@ describe('Publish endpoints - publish package', () => { beforeEach(() => { req = { body: { - name: 'verdaccio', + name: 'verdaccio' }, params: { - package: 'verdaccio', - }, + package: 'verdaccio' + } }; res = { status: jest.fn() }; next = jest.fn(); @@ -234,7 +238,7 @@ describe('Publish endpoints - publish package', () => { test('should change the existing package', () => { const storage = { - changePackage: jest.fn(), + changePackage: jest.fn() }; req.params._rev = REVISION_MOCK; @@ -246,7 +250,7 @@ describe('Publish endpoints - publish package', () => { test('should publish a new a new package', () => { const storage = { - addPackage: jest.fn(), + addPackage: jest.fn() }; // @ts-ignore @@ -258,7 +262,7 @@ describe('Publish endpoints - publish package', () => { const storage = { addPackage() { throw new Error(); - }, + } }; // @ts-ignore @@ -272,23 +276,23 @@ describe('Publish endpoints - publish package', () => { changePackage: jest.fn(), getPackage({ callback }) { callback(null, { - users: {}, + users: {} }); - }, + } }; req = { params: { - package: 'verdaccio', + package: 'verdaccio' }, body: { _rev: REVISION_MOCK, users: { - verdaccio: true, - }, + verdaccio: true + } }, remote_user: { - name: 'verdaccio', - }, + name: 'verdaccio' + } }; // @ts-ignore diff --git a/test/unit/modules/api/token.spec.ts b/test/unit/modules/api/token.spec.ts index 9800cec0b..d2b28e9a9 100644 --- a/test/unit/modules/api/token.spec.ts +++ b/test/unit/modules/api/token.spec.ts @@ -9,16 +9,17 @@ import endPointAPI from '../../../../src/api'; import { HEADERS, HTTP_STATUS, - HEADER_TYPE, TOKEN_BEARER, API_ERROR, SUPPORT_ERRORS, + HEADER_TYPE, + TOKEN_BEARER, + API_ERROR, + SUPPORT_ERRORS } from '../../../../src/lib/constants'; -import {mockServer} from '../../__helper/mock'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; +import { mockServer } from '../../__helper/mock'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; import { getNewToken } from '../../__helper/api'; -import {buildToken} from "../../../../src/lib/utils"; +import { buildToken } from '../../../../src/lib/utils'; -require('../../../../src/lib/logger').setup([ - { type: 'stdout', format: 'pretty', level: 'trace' } -]); +require('../../../../src/lib/logger').setup([{ type: 'stdout', format: 'pretty', level: 'trace' }]); const credentials = { name: 'jota_token', password: 'secretPass' }; @@ -30,13 +31,13 @@ const generateTokenCLI = async (app, token, payload): Promise => { .send(JSON.stringify(payload)) .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) - .end(function(err, resp) { + .end(function (err, resp) { if (err) { return reject([err, resp]); } resolve([err, resp]); }); - }); + }); }; const deleteTokenCLI = async (app, token, tokenToDelete): Promise => { @@ -46,7 +47,7 @@ const deleteTokenCLI = async (app, token, tokenToDelete): Promise => { .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON) .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) - .end(function(err, resp) { + .end(function (err, resp) { if (err) { return reject([err, resp]); } @@ -60,27 +61,28 @@ describe('endpoint unit test', () => { let mockRegistry; let token; - beforeAll(function(done) { + beforeAll(function (done) { const store = path.join(__dirname, '../../partials/store/test-storage-token-spec'); const mockServerPort = 55543; rimraf(store, async () => { - const configForTest = configDefault({ - auth: { - htpasswd: { - file: './test-storage-token-spec/.htpasswd-token' - } + const configForTest = configDefault( + { + auth: { + htpasswd: { + file: './test-storage-token-spec/.htpasswd-token' + } + }, + storage: store, + self_path: store, + uplinks: { + npmjs: { + url: `http://${DOMAIN_SERVERS}:${mockServerPort}` + } + }, + logs: [{ type: 'stdout', format: 'pretty', level: 'trace' }] }, - storage: store, - self_path: store, - uplinks: { - npmjs: { - url: `http://${DOMAIN_SERVERS}:${mockServerPort}` - } - }, - logs: [ - { type: 'stdout', format: 'pretty', level: 'trace' } - ] - }, 'token.spec.yaml'); + 'token.spec.yaml' + ); app = await endPointAPI(configForTest); mockRegistry = await mockServer(mockServerPort).init(); @@ -90,7 +92,7 @@ describe('endpoint unit test', () => { }); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); @@ -102,12 +104,12 @@ describe('endpoint unit test', () => { .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err, resp) { + .end(function (err, resp) { if (err) { return done(err); } - const { objects, urls} = resp.body; + const { objects, urls } = resp.body; expect(objects).toHaveLength(0); expect(urls.next).toEqual(''); done(); @@ -126,12 +128,12 @@ describe('endpoint unit test', () => { .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err, resp) { + .end(function (err, resp) { if (err) { return done(err); } - const { objects, urls} = resp.body; + const { objects, urls } = resp.body; expect(objects).toHaveLength(1); const [tokenGenerated] = objects; @@ -162,7 +164,7 @@ describe('endpoint unit test', () => { .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.OK) - .end(function(err) { + .end(function (err) { if (err) { return done(err); } @@ -211,7 +213,7 @@ describe('endpoint unit test', () => { try { const res = await generateTokenCLI(app, token, { password: credentials.password, - readonly: false, + readonly: false }); expect(res[0]).toBeNull(); diff --git a/test/unit/modules/api/validate.api.params.middleware.spec.ts b/test/unit/modules/api/validate.api.params.middleware.spec.ts index bc96a8dcc..e99dbd037 100644 --- a/test/unit/modules/api/validate.api.params.middleware.spec.ts +++ b/test/unit/modules/api/validate.api.params.middleware.spec.ts @@ -20,12 +20,14 @@ describe('api endpoint app.param()', () => { const appParams = {}; while ((m = very_scary_regexp.exec(source)) != null) { - if (m[1] === 'set') continue; + if (m[1] === 'set') { + continue; + } - let inner = m[2].slice(1, m[2].length-1); + let inner = m[2].slice(1, m[2].length - 1); let t; - inner.split('/').forEach(function(x) { + inner.split('/').forEach(function (x) { t = x.match(/^:([^?:]*)\??$/); if (m[1] === 'param') { appParams[x] = 'ok'; diff --git a/test/unit/modules/auth/auth-utils.spec.ts b/test/unit/modules/auth/auth-utils.spec.ts index 0433a6e22..97e532101 100644 --- a/test/unit/modules/auth/auth-utils.spec.ts +++ b/test/unit/modules/auth/auth-utils.spec.ts @@ -1,12 +1,12 @@ import _ from 'lodash'; import Auth from '../../../../src/lib/auth'; -import {CHARACTER_ENCODING, TOKEN_BEARER} from '../../../../src/lib/constants'; +import { CHARACTER_ENCODING, TOKEN_BEARER } from '../../../../src/lib/constants'; // $FlowFixMe import configExample from '../../partials/config'; import AppConfig from '../../../../src/lib/config'; -import {setup} from '../../../../src/lib/logger'; +import { setup } from '../../../../src/lib/logger'; -import {buildToken, convertPayloadToBase64, parseConfigFile} from '../../../../src/lib/utils'; +import { buildToken, convertPayloadToBase64, parseConfigFile } from '../../../../src/lib/utils'; import { buildUserBuffer, getApiToken, @@ -14,11 +14,11 @@ import { getMiddlewareCredentials, getSecurity } from '../../../../src/lib/auth-utils'; -import {aesDecrypt, verifyPayload} from '../../../../src/lib/crypto-utils'; -import {parseConfigurationFile} from '../../__helper'; +import { aesDecrypt, verifyPayload } from '../../../../src/lib/crypto-utils'; +import { parseConfigurationFile } from '../../__helper'; import { IAuth } from '../../../../types'; -import {Config, Security, RemoteUser} from '@verdaccio/types'; +import { Config, Security, RemoteUser } from '@verdaccio/types'; setup([]); @@ -31,7 +31,7 @@ describe('Auth utilities', () => { function getConfig(configFileName: string, secret: string) { const conf = parseConfigFile(parseConfigurationSecurityFile(configFileName)); - const secConf= _.merge(configExample(), conf); + const secConf = _.merge(configExample(), conf); secConf.secret = secret; const config: Config = new AppConfig(secConf); @@ -44,7 +44,8 @@ describe('Auth utilities', () => { password: string, secret = '12345', methodToSpy: string, - methodNotBeenCalled: string): Promise { + methodNotBeenCalled: string + ): Promise { const config: Config = getConfig(configFileName, secret); const auth: IAuth = new Auth(config); // @ts-ignore @@ -73,7 +74,9 @@ describe('Auth utilities', () => { }; const verifyAES = (token: string, user: string, password: string, secret: string) => { - const payload = aesDecrypt(convertPayloadToBase64(token), secret).toString(CHARACTER_ENCODING.UTF8); + const payload = aesDecrypt(convertPayloadToBase64(token), secret).toString( + CHARACTER_ENCODING.UTF8 + ); const content = payload.split(':'); expect(content[0]).toBe(user); @@ -82,56 +85,98 @@ describe('Auth utilities', () => { describe('getApiToken test', () => { test('should sign token with aes and security missing', async () => { - const token = await signCredentials('security-missing', - 'test', 'test', '1234567', 'aesEncrypt', 'jwtEncrypt'); + const token = await signCredentials( + 'security-missing', + 'test', + 'test', + '1234567', + 'aesEncrypt', + 'jwtEncrypt' + ); verifyAES(token, 'test', 'test', '1234567'); expect(_.isString(token)).toBeTruthy(); }); test('should sign token with aes and security empty', async () => { - const token = await signCredentials('security-empty', - 'test', 'test', '123456', 'aesEncrypt', 'jwtEncrypt'); + const token = await signCredentials( + 'security-empty', + 'test', + 'test', + '123456', + 'aesEncrypt', + 'jwtEncrypt' + ); verifyAES(token, 'test', 'test', '123456'); expect(_.isString(token)).toBeTruthy(); }); test('should sign token with aes', async () => { - const token = await signCredentials('security-basic', - 'test', 'test', '123456', 'aesEncrypt', 'jwtEncrypt'); + const token = await signCredentials( + 'security-basic', + 'test', + 'test', + '123456', + 'aesEncrypt', + 'jwtEncrypt' + ); verifyAES(token, 'test', 'test', '123456'); expect(_.isString(token)).toBeTruthy(); }); test('should sign token with legacy and jwt disabled', async () => { - const token = await signCredentials('security-no-legacy', - 'test', 'test', 'x8T#ZCx=2t', 'aesEncrypt', 'jwtEncrypt'); + const token = await signCredentials( + 'security-no-legacy', + 'test', + 'test', + 'x8T#ZCx=2t', + 'aesEncrypt', + 'jwtEncrypt' + ); expect(_.isString(token)).toBeTruthy(); verifyAES(token, 'test', 'test', 'x8T#ZCx=2t'); }); test('should sign token with legacy enabled and jwt enabled', async () => { - const token = await signCredentials('security-jwt-legacy-enabled', - 'test', 'test', 'secret', 'jwtEncrypt', 'aesEncrypt'); + const token = await signCredentials( + 'security-jwt-legacy-enabled', + 'test', + 'test', + 'secret', + 'jwtEncrypt', + 'aesEncrypt' + ); verifyJWT(token, 'test', 'test', 'secret'); expect(_.isString(token)).toBeTruthy(); }); test('should sign token with jwt enabled', async () => { - const token = await signCredentials('security-jwt', - 'test', 'test', 'secret', 'jwtEncrypt', 'aesEncrypt'); + const token = await signCredentials( + 'security-jwt', + 'test', + 'test', + 'secret', + 'jwtEncrypt', + 'aesEncrypt' + ); expect(_.isString(token)).toBeTruthy(); verifyJWT(token, 'test', 'test', 'secret'); }); test('should sign with jwt whether legacy is disabled', async () => { - const token = await signCredentials('security-legacy-disabled', - 'test', 'test', 'secret', 'jwtEncrypt', 'aesEncrypt'); + const token = await signCredentials( + 'security-legacy-disabled', + 'test', + 'test', + 'secret', + 'jwtEncrypt', + 'aesEncrypt' + ); expect(_.isString(token)).toBeTruthy(); verifyJWT(token, 'test', 'test', 'secret'); @@ -140,7 +185,7 @@ describe('Auth utilities', () => { describe('getAuthenticatedMessage test', () => { test('should sign token with jwt enabled', () => { - expect(getAuthenticatedMessage('test')).toBe('you are authenticated as \'test\''); + expect(getAuthenticatedMessage('test')).toBe("you are authenticated as 'test'"); }); }); @@ -150,8 +195,14 @@ describe('Auth utilities', () => { const secret = 'secret'; const user = 'test'; const pass = 'test'; - const token = await signCredentials('security-legacy', - user, pass, secret, 'aesEncrypt', 'jwtEncrypt'); + const token = await signCredentials( + 'security-legacy', + user, + pass, + secret, + 'aesEncrypt', + 'jwtEncrypt' + ); const config: Config = getConfig('security-legacy', secret); const security: Security = getSecurity(config); const credentials = getMiddlewareCredentials(security, secret, `Bearer ${token}`); @@ -179,21 +230,41 @@ describe('Auth utilities', () => { test.concurrent('should return empty credential wrong secret key', async () => { const secret = 'secret'; - const token = await signCredentials('security-legacy', - 'test', 'test', secret, 'aesEncrypt', 'jwtEncrypt'); + const token = await signCredentials( + 'security-legacy', + 'test', + 'test', + secret, + 'aesEncrypt', + 'jwtEncrypt' + ); const config: Config = getConfig('security-legacy', secret); const security: Security = getSecurity(config); - const credentials = getMiddlewareCredentials(security, 'BAD_SECRET', buildToken(TOKEN_BEARER, token)); + const credentials = getMiddlewareCredentials( + security, + 'BAD_SECRET', + buildToken(TOKEN_BEARER, token) + ); expect(credentials).not.toBeDefined(); }); test.concurrent('should return empty credential wrong scheme', async () => { const secret = 'secret'; - const token = await signCredentials('security-legacy', - 'test', 'test', secret, 'aesEncrypt', 'jwtEncrypt'); + const token = await signCredentials( + 'security-legacy', + 'test', + 'test', + secret, + 'aesEncrypt', + 'jwtEncrypt' + ); const config: Config = getConfig('security-legacy', secret); const security: Security = getSecurity(config); - const credentials = getMiddlewareCredentials(security, secret, buildToken('BAD_SCHEME', token)); + const credentials = getMiddlewareCredentials( + security, + secret, + buildToken('BAD_SCHEME', token) + ); expect(credentials).not.toBeDefined(); }); @@ -203,7 +274,11 @@ describe('Auth utilities', () => { const auth: IAuth = new Auth(config); const token = auth.aesEncrypt(Buffer.from(`corruptedBuffer`)).toString('base64'); const security: Security = getSecurity(config); - const credentials = getMiddlewareCredentials(security, secret, buildToken(TOKEN_BEARER, token)); + const credentials = getMiddlewareCredentials( + security, + secret, + buildToken(TOKEN_BEARER, token) + ); expect(credentials).not.toBeDefined(); }); }); @@ -212,7 +287,11 @@ describe('Auth utilities', () => { test('should return anonymous whether token is corrupted', () => { const config: Config = getConfig('security-jwt', '12345'); const security: Security = getSecurity(config); - const credentials = getMiddlewareCredentials(security, '12345', buildToken(TOKEN_BEARER, 'fakeToken')); + const credentials = getMiddlewareCredentials( + security, + '12345', + buildToken(TOKEN_BEARER, 'fakeToken') + ); expect(credentials).toBeDefined(); // @ts-ignore @@ -226,7 +305,11 @@ describe('Auth utilities', () => { test('should return anonymous whether token and scheme are corrupted', () => { const config: Config = getConfig('security-jwt', '12345'); const security: Security = getSecurity(config); - const credentials = getMiddlewareCredentials(security, '12345', buildToken('FakeScheme', 'fakeToken')); + const credentials = getMiddlewareCredentials( + security, + '12345', + buildToken('FakeScheme', 'fakeToken') + ); expect(credentials).not.toBeDefined(); }); @@ -235,10 +318,20 @@ describe('Auth utilities', () => { const secret = 'secret'; const user = 'test'; const config: Config = getConfig('security-jwt', secret); - const token = await signCredentials('security-jwt', - user, 'secretTest', secret, 'jwtEncrypt', 'aesEncrypt'); + const token = await signCredentials( + 'security-jwt', + user, + 'secretTest', + secret, + 'jwtEncrypt', + 'aesEncrypt' + ); const security: Security = getSecurity(config); - const credentials = getMiddlewareCredentials(security, secret, buildToken(TOKEN_BEARER, token)); + const credentials = getMiddlewareCredentials( + security, + secret, + buildToken(TOKEN_BEARER, token) + ); expect(credentials).toBeDefined(); // @ts-ignore expect(credentials.name).toEqual(user); diff --git a/test/unit/modules/auth/crypto-utils.spec.ts b/test/unit/modules/auth/crypto-utils.spec.ts index a3446b618..d94288768 100644 --- a/test/unit/modules/auth/crypto-utils.spec.ts +++ b/test/unit/modules/auth/crypto-utils.spec.ts @@ -1,15 +1,15 @@ -import {aesDecrypt, aesEncrypt} from "../../../../src/lib/crypto-utils"; -import {convertPayloadToBase64} from "../../../../src/lib/utils"; +import { aesDecrypt, aesEncrypt } from '../../../../src/lib/crypto-utils'; +import { convertPayloadToBase64 } from '../../../../src/lib/utils'; describe('test crypto utils', () => { - describe('default encryption', () => { - test('decrypt payload flow', () => { - const payload = 'juan'; - const token = aesEncrypt(Buffer.from(payload), '12345').toString('base64'); + describe('default encryption', () => { + test('decrypt payload flow', () => { + const payload = 'juan'; + const token = aesEncrypt(Buffer.from(payload), '12345').toString('base64'); - const data = aesDecrypt(convertPayloadToBase64(token), '12345').toString('utf8'); + const data = aesDecrypt(convertPayloadToBase64(token), '12345').toString('utf8'); - expect(payload).toEqual(data); - }); - }); + expect(payload).toEqual(data); + }); + }); }); diff --git a/test/unit/modules/auth/jwt.spec.ts b/test/unit/modules/auth/jwt.spec.ts index cc9722609..fdb810bfe 100644 --- a/test/unit/modules/auth/jwt.spec.ts +++ b/test/unit/modules/auth/jwt.spec.ts @@ -4,14 +4,21 @@ import rimraf from 'rimraf'; import endPointAPI from '../../../../src/api'; -import {HEADERS, HTTP_STATUS, HEADER_TYPE, TOKEN_BEARER, TOKEN_BASIC, API_ERROR} from '../../../../src/lib/constants'; -import {mockServer} from '../../__helper/mock'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; -import {buildToken} from '../../../../src/lib/utils'; -import {addUser, getPackage, loginUserToken} from '../../__helper/api'; -import {setup} from '../../../../src/lib/logger'; +import { + HEADERS, + HTTP_STATUS, + HEADER_TYPE, + TOKEN_BEARER, + TOKEN_BASIC, + API_ERROR +} from '../../../../src/lib/constants'; +import { mockServer } from '../../__helper/mock'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; +import { buildToken } from '../../../../src/lib/utils'; +import { addUser, getPackage, loginUserToken } from '../../__helper/api'; +import { setup } from '../../../../src/lib/logger'; import configDefault from '../../partials/config'; -import {buildUserBuffer} from '../../../../src/lib/auth-utils'; +import { buildUserBuffer } from '../../../../src/lib/auth-utils'; setup([]); const credentials = { name: 'JotaJWT', password: 'secretPass' }; @@ -24,27 +31,28 @@ describe('endpoint user auth JWT unit test', () => { let mockRegistry; const FAKE_TOKEN: string = buildToken(TOKEN_BEARER, 'fake'); - beforeAll(function(done) { + beforeAll(function (done) { const store = path.join(__dirname, '../../partials/store/test-jwt-storage'); const mockServerPort = 55546; rimraf(store, async () => { - const configForTest = configDefault({ - storage: store, - uplinks: { - npmjs: { - url: `http://${DOMAIN_SERVERS}:${mockServerPort}` - } + const configForTest = configDefault( + { + storage: store, + uplinks: { + npmjs: { + url: `http://${DOMAIN_SERVERS}:${mockServerPort}` + } + }, + self_path: store, + auth: { + htpasswd: { + file: './test-jwt-storage/.htpasswd_jwt_auth' + } + }, + logs: [{ type: 'stdout', format: 'pretty', level: 'warn' }] }, - self_path: store, - auth: { - htpasswd: { - file: './test-jwt-storage/.htpasswd_jwt_auth' - } - }, - logs: [ - { type: 'stdout', format: 'pretty', level: 'warn' } - ] - }, 'api-jwt/jwt.yaml'); + 'api-jwt/jwt.yaml' + ); app = await endPointAPI(configForTest); mockRegistry = await mockServer(mockServerPort).init(); @@ -52,7 +60,7 @@ describe('endpoint user auth JWT unit test', () => { }); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); @@ -74,7 +82,12 @@ describe('endpoint user auth JWT unit test', () => { expect(resp1.body).toBeDefined(); expect(resp1.body.name).toMatch('vue'); - const [err2, resp2] = await getPackage(request(app), FAKE_TOKEN, 'vue', HTTP_STATUS.UNAUTHORIZED); + const [err2, resp2] = await getPackage( + request(app), + FAKE_TOKEN, + 'vue', + HTTP_STATUS.UNAUTHORIZED + ); expect(err2).toBeNull(); expect(resp2.statusCode).toBe(HTTP_STATUS.UNAUTHORIZED); expect(resp2.body.error).toMatch(FORBIDDEN_VUE); @@ -92,12 +105,13 @@ describe('endpoint user auth JWT unit test', () => { const token = buildUserBuffer(credentials.name, credentials.password).toString('base64'); // put should exist in request // @ts-ignore - request(app).put(`/-/user/org.couchdb.user:${credentials.name}/-rev/undefined`) + request(app) + .put(`/-/user/org.couchdb.user:${credentials.name}/-rev/undefined`) .send(credentials) .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BASIC, token)) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) .expect(HTTP_STATUS.CREATED) - .end(function(err, res) { + .end(function (err, res) { expect(err).toBeNull(); expect(res.body.ok).toBeDefined(); expect(res.body.token).toBeDefined(); @@ -107,7 +121,12 @@ describe('endpoint user auth JWT unit test', () => { }); test('should fails on try to access with corrupted token', async (done) => { - const [err2, resp2] = await getPackage(request(app), FAKE_TOKEN, 'vue', HTTP_STATUS.UNAUTHORIZED); + const [err2, resp2] = await getPackage( + request(app), + FAKE_TOKEN, + 'vue', + HTTP_STATUS.UNAUTHORIZED + ); expect(err2).toBeNull(); expect(resp2.statusCode).toBe(HTTP_STATUS.UNAUTHORIZED); expect(resp2.body.error).toMatch(FORBIDDEN_VUE); @@ -127,7 +146,13 @@ describe('endpoint user auth JWT unit test', () => { // we login when token is valid const newCredentials = { name: 'newFailsUser', password: 'BAD_PASSWORD' }; - const [err2, resp2] = await loginUserToken(request(app), newCredentials.name, newCredentials, token, HTTP_STATUS.UNAUTHORIZED); + const [err2, resp2] = await loginUserToken( + request(app), + newCredentials.name, + newCredentials, + token, + HTTP_STATUS.UNAUTHORIZED + ); expect(err2).toBeNull(); expect(resp2.statusCode).toBe(HTTP_STATUS.UNAUTHORIZED); expect(resp2.body.error).toMatch(API_ERROR.BAD_USERNAME_PASSWORD); diff --git a/test/unit/modules/auth/profile.spec.ts b/test/unit/modules/auth/profile.spec.ts index d9e3bf19d..1c2d6abe5 100644 --- a/test/unit/modules/auth/profile.spec.ts +++ b/test/unit/modules/auth/profile.spec.ts @@ -4,12 +4,12 @@ import path from 'path'; import rimraf from 'rimraf'; import endPointAPI from '../../../../src/api'; -import {mockServer} from '../../__helper/mock'; -import {parseConfigFile} from '../../../../src/lib/utils'; -import {parseConfigurationFile} from '../../__helper'; -import {getNewToken, getProfile, postProfile} from '../../__helper/api'; -import {setup} from '../../../../src/lib/logger'; -import {API_ERROR, HTTP_STATUS, SUPPORT_ERRORS} from '../../../../src/lib/constants'; +import { mockServer } from '../../__helper/mock'; +import { parseConfigFile } from '../../../../src/lib/utils'; +import { parseConfigurationFile } from '../../__helper'; +import { getNewToken, getProfile, postProfile } from '../../__helper/api'; +import { setup } from '../../../../src/lib/logger'; +import { API_ERROR, HTTP_STATUS, SUPPORT_ERRORS } from '../../../../src/lib/constants'; setup([]); @@ -22,7 +22,7 @@ describe('endpoint user profile', () => { let mockRegistry; jest.setTimeout(20000); - beforeAll(function(done) { + beforeAll(function (done) { const store = path.join(__dirname, '../../partials/store/test-profile-storage'); const mockServerPort = 55544; rimraf(store, async () => { @@ -42,7 +42,7 @@ describe('endpoint user profile', () => { }); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); @@ -63,7 +63,7 @@ describe('endpoint user profile', () => { const body = { password: { new: '12345678', - old: credentials.password, + old: credentials.password } }; const token = await getNewToken(request(app), credentials); @@ -79,7 +79,7 @@ describe('endpoint user profile', () => { const body = { password: { new: 'p1', - old: credentials.password, + old: credentials.password } }; const token = await getNewToken(request(app), credentials); @@ -99,7 +99,12 @@ describe('endpoint user profile', () => { tfa: {} }; const token = await getNewToken(request(app), credentials); - const [, resp] = await postProfile(request(app), body, token, HTTP_STATUS.SERVICE_UNAVAILABLE); + const [, resp] = await postProfile( + request(app), + body, + token, + HTTP_STATUS.SERVICE_UNAVAILABLE + ); expect(resp.error).not.toBeNull(); expect(resp.error.text).toMatch(SUPPORT_ERRORS.TFA_DISABLED); diff --git a/test/unit/modules/basic_system.spec.ts b/test/unit/modules/basic_system.spec.ts index 37a0b4e2a..2c1ea5e24 100644 --- a/test/unit/modules/basic_system.spec.ts +++ b/test/unit/modules/basic_system.spec.ts @@ -1,5 +1,5 @@ import endPointAPI from '../../../src/api/index'; -import {API_ERROR} from '../../../src/lib/constants'; +import { API_ERROR } from '../../../src/lib/constants'; import express from 'express'; import request from 'request'; @@ -8,9 +8,7 @@ import config from '../partials/config/index'; import { setup } from '../../../src/lib/logger'; -setup([ - {type: 'stdout', format: 'pretty', level: 'trace'} -]); +setup([{ type: 'stdout', format: 'pretty', level: 'trace' }]); const app = express(); const server = require('http').createServer(app); @@ -19,15 +17,14 @@ describe('basic system test', () => { let port; jest.setTimeout(20000); - beforeAll(function(done) { + beforeAll(function (done) { rimraf(__dirname + '/store/test-storage', done); }); - beforeAll(async function(done) { - + beforeAll(async function (done) { app.use(await endPointAPI(config())); - server.listen(0, function() { + server.listen(0, function () { port = server.address().port; done(); }); @@ -37,23 +34,29 @@ describe('basic system test', () => { server.close(done); }); - test('server should respond on /', done => { - request({ - url: 'http://localhost:' + port + '/', - }, function(err, res, body) { - expect(err).toBeNull(); - expect(body).toMatch(/Verdaccio/); - done(); - }); + test('server should respond on /', (done) => { + request( + { + url: 'http://localhost:' + port + '/' + }, + function (err, res, body) { + expect(err).toBeNull(); + expect(body).toMatch(/Verdaccio/); + done(); + } + ); }); - test('server should respond on /___not_found_package', done => { - request({ - url: `http://localhost:${port}/___not_found_package`, - }, function(err, res, body) { - expect(err).toBeNull(); - expect(body).toMatch(API_ERROR.NO_PACKAGE); - done(); - }); + test('server should respond on /___not_found_package', (done) => { + request( + { + url: `http://localhost:${port}/___not_found_package` + }, + function (err, res, body) { + expect(err).toBeNull(); + expect(body).toMatch(API_ERROR.NO_PACKAGE); + done(); + } + ); }); }); diff --git a/test/unit/modules/cli/cli.spec.ts b/test/unit/modules/cli/cli.spec.ts index d789d8a89..a3a1603fe 100644 --- a/test/unit/modules/cli/cli.spec.ts +++ b/test/unit/modules/cli/cli.spec.ts @@ -6,9 +6,9 @@ import fs from 'fs'; import startServer from '../../../../src'; import config from '../../partials/config'; -import {DEFAULT_DOMAIN, DEFAULT_PORT, DEFAULT_PROTOCOL} from '../../../../src/lib/constants'; -import {getListListenAddresses} from '../../../../src/lib/cli/utils'; -import {parseConfigFile} from '../../../../src/lib/utils'; +import { DEFAULT_DOMAIN, DEFAULT_PORT, DEFAULT_PROTOCOL } from '../../../../src/lib/constants'; +import { getListListenAddresses } from '../../../../src/lib/cli/utils'; +import { parseConfigFile } from '../../../../src/lib/utils'; import { logger } from '../../../../src/lib/logger'; jest.mock('../../../../src/lib/logger', () => ({ @@ -24,7 +24,6 @@ jest.mock('../../../../src/lib/logger', () => ({ })); describe('startServer via API', () => { - const parseConfigurationFile = (name) => { return parseConfigFile(path.join(__dirname, `../../partials/config/yaml/${name}.yaml`)); }; @@ -36,7 +35,12 @@ describe('startServer via API', () => { const version = '1.0.0'; const port = '6000'; - await startServer(config(), port, store, version, serverName, + await startServer( + config(), + port, + store, + version, + serverName, (webServer, addrs, pkgName, pkgVersion) => { expect(webServer).toBeDefined(); expect(addrs).toBeDefined(); @@ -48,7 +52,8 @@ describe('startServer via API', () => { expect(pkgVersion).toBe(version); expect(pkgName).toBe(serverName); done(); - }); + } + ); }); test('should set keepAliveTimeout to 0 seconds', async (done) => { @@ -57,7 +62,12 @@ describe('startServer via API', () => { const version = '1.0.0'; const port = '6100'; - await startServer(config(parseConfigurationFile('server/keepalivetimeout-0')), port, store, version, serverName, + await startServer( + config(parseConfigurationFile('server/keepalivetimeout-0')), + port, + store, + version, + serverName, (webServer, addrs, pkgName, pkgVersion) => { expect(webServer).toBeDefined(); expect(webServer.keepAliveTimeout).toBeDefined(); @@ -71,7 +81,8 @@ describe('startServer via API', () => { expect(pkgVersion).toBe(version); expect(pkgName).toBe(serverName); done(); - }); + } + ); }); test('should set keepAliveTimeout to 60 seconds', async (done) => { @@ -80,7 +91,12 @@ describe('startServer via API', () => { const version = '1.0.0'; const port = '6200'; - await startServer(config(parseConfigurationFile('server/keepalivetimeout-60')), port, store, version, serverName, + await startServer( + config(parseConfigurationFile('server/keepalivetimeout-60')), + port, + store, + version, + serverName, (webServer, addrs, pkgName, pkgVersion) => { expect(webServer).toBeDefined(); expect(webServer.keepAliveTimeout).toBeDefined(); @@ -94,7 +110,8 @@ describe('startServer via API', () => { expect(pkgVersion).toBe(version); expect(pkgName).toBe(serverName); done(); - }); + } + ); }); test('should set keepAliveTimeout to 5 seconds per default', async (done) => { @@ -103,7 +120,12 @@ describe('startServer via API', () => { const version = '1.0.0'; const port = '6300'; - await startServer(config(parseConfigurationFile('server/keepalivetimeout-undefined')), port, store, version, serverName, + await startServer( + config(parseConfigurationFile('server/keepalivetimeout-undefined')), + port, + store, + version, + serverName, (webServer, addrs, pkgName, pkgVersion) => { expect(webServer).toBeDefined(); expect(webServer.keepAliveTimeout).toBeDefined(); @@ -117,7 +139,8 @@ describe('startServer via API', () => { expect(pkgVersion).toBe(version); expect(pkgName).toBe(serverName); done(); - }); + } + ); }); test('should provide all HTTPS server fails', async (done) => { @@ -157,17 +180,16 @@ describe('startServer via API', () => { const conf = config(); conf.https = { key: keyPath, - cert: certPath, + cert: certPath }; - await startServer(conf, address, store, version, serverName, - (webServer, addrs) => { - expect(webServer).toBeDefined(); - expect(addrs).toBeDefined(); - expect(addrs.proto).toBe('https'); - done(); + await startServer(conf, address, store, version, serverName, (webServer, addrs) => { + expect(webServer).toBeDefined(); + expect(addrs).toBeDefined(); + expect(addrs.proto).toBe('https'); + done(); }); - }) + }); test('should fails if config is missing', async () => { try { @@ -177,14 +199,12 @@ describe('startServer via API', () => { expect(e.message).toEqual('config file must be an object'); } }); - }); describe('getListListenAddresses test', () => { - test('should return no address if a single address is wrong', () => { // @ts-ignore - const addrs = getListListenAddresses("wrong"); + const addrs = getListListenAddresses('wrong'); expect(_.isArray(addrs)).toBeTruthy(); expect(addrs).toHaveLength(0); @@ -192,7 +212,7 @@ describe('startServer via API', () => { test('should return no address if a two address are wrong', () => { // @ts-ignore - const addrs = getListListenAddresses(["wrong", "same-wrong"]); + const addrs = getListListenAddresses(['wrong', 'same-wrong']); expect(_.isArray(addrs)).toBeTruthy(); expect(addrs).toHaveLength(0); @@ -238,7 +258,5 @@ describe('startServer via API', () => { // @ts-ignore expect(addrs.port).toEqual(initPort); }); - }); - }); diff --git a/test/unit/modules/cli/parseAddress.spec.ts b/test/unit/modules/cli/parseAddress.spec.ts index 78649fc49..d2d897322 100644 --- a/test/unit/modules/cli/parseAddress.spec.ts +++ b/test/unit/modules/cli/parseAddress.spec.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -import {parseAddress as parse} from '../../../../src/lib/utils'; -import {DEFAULT_DOMAIN, DEFAULT_PORT} from '../../../../src/lib/constants'; +import { parseAddress as parse } from '../../../../src/lib/utils'; +import { DEFAULT_DOMAIN, DEFAULT_PORT } from '../../../../src/lib/constants'; describe('Parse listen address', () => { const useCases: any[] = []; @@ -39,12 +39,12 @@ describe('Parse listen address', () => { expect(parsed).toEqual({ proto, host, - port, + port }); } else { expect(parsed).toEqual({ proto, - path: host, + path: host }); } }); diff --git a/test/unit/modules/config/config.spec.ts b/test/unit/modules/config/config.spec.ts index d232a9ff1..3ec62859b 100644 --- a/test/unit/modules/config/config.spec.ts +++ b/test/unit/modules/config/config.spec.ts @@ -2,8 +2,8 @@ import path from 'path'; import _ from 'lodash'; import Config from '../../../../src/lib/config'; -import {parseConfigFile} from '../../../../src/lib/utils'; -import {DEFAULT_REGISTRY, DEFAULT_UPLINK, ROLES, WEB_TITLE} from '../../../../src/lib/constants'; +import { parseConfigFile } from '../../../../src/lib/utils'; +import { DEFAULT_REGISTRY, DEFAULT_UPLINK, ROLES, WEB_TITLE } from '../../../../src/lib/constants'; import { setup } from '../../../../src/lib/logger'; setup([]); @@ -43,7 +43,7 @@ const checkDefaultConfPackages = (config) => { expect(config.packages['**'].publish).toBeDefined(); expect(config.packages['**'].publish).toContainEqual(ROLES.$AUTH); expect(config.packages['**'].proxy).toBeDefined(); - expect(config.packages['**'].proxy,).toContainEqual(DEFAULT_UPLINK); + expect(config.packages['**'].proxy).toContainEqual(DEFAULT_UPLINK); // uplinks expect(config.uplinks[DEFAULT_UPLINK]).toBeDefined(); expect(config.uplinks[DEFAULT_UPLINK].url).toEqual(DEFAULT_REGISTRY); @@ -68,7 +68,7 @@ const checkDefaultConfPackages = (config) => { }; describe('Config file', () => { - beforeAll(function() { + beforeAll(function () { /* eslint no-invalid-this: 0 */ // @ts-ignore this.config = new Config(parseConfigFile(resolveConf('default'))); @@ -94,9 +94,5 @@ describe('Config file', () => { }); }); - describe('Config file', () => { - - }); - + describe('Config file', () => {}); }); - diff --git a/test/unit/modules/logger/parser.spec.ts b/test/unit/modules/logger/parser.spec.ts index 6e984c54a..1863c8a06 100644 --- a/test/unit/modules/logger/parser.spec.ts +++ b/test/unit/modules/logger/parser.spec.ts @@ -1,21 +1,21 @@ -import { fillInMsgTemplate } from "../../../../src/lib/logger/formatter"; -import {LOG_VERDACCIO_ERROR, LOG_VERDACCIO_BYTES} from "../../../../src/api/middleware"; -import { HTTP_STATUS } from "@verdaccio/commons-api"; +import { fillInMsgTemplate } from '../../../../src/lib/logger/formatter'; +import { LOG_VERDACCIO_ERROR, LOG_VERDACCIO_BYTES } from '../../../../src/api/middleware'; +import { HTTP_STATUS } from '@verdaccio/commons-api'; // the following mocks avoid use colors, thus the strings can be matched jest.mock('kleur', () => { // we emulate colors with this pattern color[msg] return { - green: r => `g[${r}]`, - yellow: r => `y[${r}]`, - black: r => `b[${r}]`, - blue: r => `bu[${r}]`, - red: r => `r[${r}]`, - cyan: r => `c[${r}]`, - magenta: r => `m[${r}]`, - white: r => `w[${r}]`, - } + green: (r) => `g[${r}]`, + yellow: (r) => `y[${r}]`, + black: (r) => `b[${r}]`, + blue: (r) => `bu[${r}]`, + red: (r) => `r[${r}]`, + cyan: (r) => `c[${r}]`, + magenta: (r) => `m[${r}]`, + white: (r) => `w[${r}]` + }; }); jest.mock('util', () => { @@ -23,19 +23,18 @@ jest.mock('util', () => { const originalModule = jest.requireActual('util'); return { ...originalModule, - inspect: r => r, - } + inspect: (r) => r + }; }); - describe('Logger Parser', () => { describe('basic messages', () => { test('number object property', () => { - expect(fillInMsgTemplate('foo:@{foo}', {foo: 1}, false)).toEqual('foo:1'); + expect(fillInMsgTemplate('foo:@{foo}', { foo: 1 }, false)).toEqual('foo:1'); }); test('string object property', () => { - expect(fillInMsgTemplate('foo:@{foo}', {foo: 'bar'}, false)).toEqual('foo:bar'); + expect(fillInMsgTemplate('foo:@{foo}', { foo: 'bar' }, false)).toEqual('foo:bar'); }); test('empty message no object property', () => { @@ -46,7 +45,7 @@ describe('Logger Parser', () => { expect(fillInMsgTemplate('foo', null, false)).toEqual('foo'); }); - test('string no object property with break line ', () => { + test('string no object property with break line', () => { expect(fillInMsgTemplate('foo \n bar', null, false)).toEqual('foo \n bar'); }); @@ -55,13 +54,14 @@ describe('Logger Parser', () => { }); test('string object property with colors', () => { - expect(fillInMsgTemplate('foo:@{foo}', {foo: 'bar'}, true)).toEqual(`foo:${'g[bar]'}`); + expect(fillInMsgTemplate('foo:@{foo}', { foo: 'bar' }, true)).toEqual(`foo:${'g[bar]'}`); }); - }) + }); describe('middleware log messages', () => { describe('test errors log', () => { - const middlewareObject = { name: 'verdaccio', + const middlewareObject = { + name: 'verdaccio', request: { method: 'POST', url: '/-/npm/v1/user' @@ -70,24 +70,28 @@ describe('Logger Parser', () => { remoteIP: '::ffff:127.0.0.1', status: HTTP_STATUS.UNAUTHORIZED, error: 'some error', - msg: '@{status}, user: @{user}(@{remoteIP}), req: \'@{request.method} @{request.url}\', error: @{!error}' + msg: + "@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}', error: @{!error}" }; test('should display error log', () => { const expectedErrorMessage = `401, user: userTest2001(::ffff:127.0.0.1), req: 'POST /-/npm/v1/user', error: some error`; - expect(fillInMsgTemplate(LOG_VERDACCIO_ERROR, middlewareObject, false)) - .toEqual(expectedErrorMessage); + expect(fillInMsgTemplate(LOG_VERDACCIO_ERROR, middlewareObject, false)).toEqual( + expectedErrorMessage + ); }); test('should display error log with colors', () => { const expectedErrorMessage = `401, user: g[userTest2001](g[::ffff:127.0.0.1]), req: 'g[POST] g[/-/npm/v1/user]', error: r[some error]`; - expect(fillInMsgTemplate(LOG_VERDACCIO_ERROR, middlewareObject, true)) - .toEqual(expectedErrorMessage); + expect(fillInMsgTemplate(LOG_VERDACCIO_ERROR, middlewareObject, true)).toEqual( + expectedErrorMessage + ); }); }); describe('test bytes log', () => { - const middlewareObject = { name: 'verdaccio', + const middlewareObject = { + name: 'verdaccio', hostname: 'macbook-touch', pid: 85621, sub: 'in', @@ -102,19 +106,21 @@ describe('Logger Parser', () => { error: undefined, bytes: { in: 50, out: 405 }, msg: - '@{status}, user: @{user}(@{remoteIP}), req: \'@{request.method} @{request.url}\', bytes: @{bytes.in}/@{bytes.out}', + "@{status}, user: @{user}(@{remoteIP}), req: '@{request.method} @{request.url}', bytes: @{bytes.in}/@{bytes.out}", time: '2019-07-20T11:31:49.939Z', v: 0 - } + }; test('should display log with bytes', () => { - expect(fillInMsgTemplate(LOG_VERDACCIO_BYTES, middlewareObject, false)) - .toEqual(`201, user: userTest2002(::ffff:127.0.0.1), req: 'PUT /-/user/org.couchdb.user:userTest2002', bytes: 50/405`); + expect(fillInMsgTemplate(LOG_VERDACCIO_BYTES, middlewareObject, false)).toEqual( + `201, user: userTest2002(::ffff:127.0.0.1), req: 'PUT /-/user/org.couchdb.user:userTest2002', bytes: 50/405` + ); }); test('should display log with bytes with colors', () => { - expect(fillInMsgTemplate(LOG_VERDACCIO_BYTES, middlewareObject, true)) - .toEqual(`201, user: g[userTest2002](g[::ffff:127.0.0.1]), req: 'g[PUT] g[/-/user/org.couchdb.user:userTest2002]', bytes: 50/405`); + expect(fillInMsgTemplate(LOG_VERDACCIO_BYTES, middlewareObject, true)).toEqual( + `201, user: g[userTest2002](g[::ffff:127.0.0.1]), req: 'g[PUT] g[/-/user/org.couchdb.user:userTest2002]', bytes: 50/405` + ); }); }); }); diff --git a/test/unit/modules/notifications/notify.spec.ts b/test/unit/modules/notifications/notify.spec.ts index 26cc3dbbf..f1df3066e 100644 --- a/test/unit/modules/notifications/notify.spec.ts +++ b/test/unit/modules/notifications/notify.spec.ts @@ -1,8 +1,8 @@ -import {parseConfigurationFile} from '../../__helper'; -import {parseConfigFile} from '../../../../src/lib/utils'; -import {notify} from '../../../../src/lib/notify'; +import { parseConfigurationFile } from '../../__helper'; +import { parseConfigFile } from '../../../../src/lib/utils'; +import { notify } from '../../../../src/lib/notify'; -import {notifyRequest} from '../../../../src/lib/notify/notify-request'; +import { notifyRequest } from '../../../../src/lib/notify/notify-request'; import { setup } from '../../../../src/lib/logger'; @@ -16,29 +16,32 @@ const parseConfigurationNotifyFile = (name) => { return parseConfigurationFile(`notify/${name}`); }; const singleNotificationConfig = parseConfigFile(parseConfigurationNotifyFile('single.notify')); -const singleHeaderNotificationConfig = parseConfigFile(parseConfigurationNotifyFile('single.header.notify')); -const packagePatternNotificationConfig = parseConfigFile(parseConfigurationNotifyFile('single.packagePattern.notify')); +const singleHeaderNotificationConfig = parseConfigFile( + parseConfigurationNotifyFile('single.header.notify') +); +const packagePatternNotificationConfig = parseConfigFile( + parseConfigurationNotifyFile('single.packagePattern.notify') +); const multiNotificationConfig = parseConfigFile(parseConfigurationNotifyFile('multiple.notify')); describe('Notifications:: Notify', () => { - beforeEach(() => { jest.clearAllMocks(); }); // FUTURE: we should add some sort of health check of all props, (not implemented yet) - test("should not fails if config is not provided", async () => { + test('should not fails if config is not provided', async () => { // @ts-ignore await notify({}, {}); expect(notifyRequest).toHaveBeenCalledTimes(0); }); - test("should send notification", async () => { + test('should send notification', async () => { const name = 'package'; // @ts-ignore - const response = await notify({name}, singleNotificationConfig, { name: 'foo'}, 'bar'); + const response = await notify({ name }, singleNotificationConfig, { name: 'foo' }, 'bar'); const [options, content] = response; expect(options.headers).toBeDefined(); @@ -49,39 +52,36 @@ describe('Notifications:: Notify', () => { expect(notifyRequest).toHaveBeenCalledTimes(1); }); - test("should send single header notification", async () => { + test('should send single header notification', async () => { // @ts-ignore - await notify({}, singleHeaderNotificationConfig, { name: 'foo'}, 'bar'); + await notify({}, singleHeaderNotificationConfig, { name: 'foo' }, 'bar'); expect(notifyRequest).toHaveBeenCalledTimes(1); }); - test("should send multiple notification", async () => { + test('should send multiple notification', async () => { // @ts-ignore - await notify({name}, multiNotificationConfig, { name: 'foo'}, 'bar'); + await notify({ name }, multiNotificationConfig, { name: 'foo' }, 'bar'); expect(notifyRequest).toHaveBeenCalled(); expect(notifyRequest).toHaveBeenCalledTimes(3); }); describe('packagePatternFlags', () => { - test("should send single notification with packagePatternFlags", async () => { + test('should send single notification with packagePatternFlags', async () => { const name = 'package'; // @ts-ignore - await notify({name}, packagePatternNotificationConfig, { name: 'foo'}, 'bar'); - + await notify({ name }, packagePatternNotificationConfig, { name: 'foo' }, 'bar'); expect(notifyRequest).toHaveBeenCalledTimes(1); }); - test("should not match on send single notification with packagePatternFlags", async () => { + test('should not match on send single notification with packagePatternFlags', async () => { const name = 'no-mach-name'; // @ts-ignore - await notify({name}, packagePatternNotificationConfig, { name: 'foo'}, 'bar'); + await notify({ name }, packagePatternNotificationConfig, { name: 'foo' }, 'bar'); expect(notifyRequest).toHaveBeenCalledTimes(0); }); - }) - - + }); }); diff --git a/test/unit/modules/notifications/request.spec.ts b/test/unit/modules/notifications/request.spec.ts index f4d05e991..d7f0ff752 100644 --- a/test/unit/modules/notifications/request.spec.ts +++ b/test/unit/modules/notifications/request.spec.ts @@ -8,8 +8,8 @@ const logger = { logger: { error: jest.fn(), debug: jest.fn(), - info: jest.fn(), - }, + info: jest.fn() + } }; jest.doMock('../../../../src/lib/logger', () => logger); @@ -17,7 +17,7 @@ jest.doMock('../../../../src/lib/logger', () => logger); * Test Data */ const options = { - url: 'http://slack-service', + url: 'http://slack-service' }; const content = 'Verdaccio@x.x.x successfully published'; @@ -29,16 +29,19 @@ describe('Notifications:: notifyRequest', () => { test('when notification service throws error', async () => { jest.doMock('request', () => (options, resolver) => { const response = { - statusCode: HTTP_STATUS.BAD_REQUEST, + statusCode: HTTP_STATUS.BAD_REQUEST }; const error = { - message: API_ERROR.BAD_DATA, + message: API_ERROR.BAD_DATA }; resolver(error, response); }); const notification = require('../../../../src/lib/notify/notify-request'); - const args = [{ errorMessage: 'bad data' }, 'notify service has thrown an error: @{errorMessage}']; + const args = [ + { errorMessage: 'bad data' }, + 'notify service has thrown an error: @{errorMessage}' + ]; await expect(notification.notifyRequest(options, content)).rejects.toEqual(API_ERROR.BAD_DATA); expect(logger.logger.error).toHaveBeenCalledWith(...args); @@ -48,14 +51,17 @@ describe('Notifications:: notifyRequest', () => { jest.doMock('request', () => (options, resolver) => { const response = { statusCode: HTTP_STATUS.BAD_REQUEST, - body: API_ERROR.BAD_DATA, + body: API_ERROR.BAD_DATA }; resolver(null, response); }); const notification = require('../../../../src/lib/notify/notify-request'); - const args = [{ errorMessage: 'bad data' }, 'notify service has thrown an error: @{errorMessage}']; + const args = [ + { errorMessage: 'bad data' }, + 'notify service has thrown an error: @{errorMessage}' + ]; await expect(notification.notifyRequest(options, content)).rejects.toEqual(API_ERROR.BAD_DATA); expect(logger.logger.error).toHaveBeenCalledWith(...args); @@ -65,7 +71,7 @@ describe('Notifications:: notifyRequest', () => { jest.doMock('request', () => (options, resolver) => { const response = { statusCode: HTTP_STATUS.OK, - body: 'Successfully delivered', + body: 'Successfully delivered' }; resolver(null, response, response.body); @@ -75,7 +81,9 @@ describe('Notifications:: notifyRequest', () => { const infoArgs = [{ content }, 'A notification has been shipped: @{content}']; const debugArgs = [{ body: 'Successfully delivered' }, ' body: @{body}']; - await expect(notification.notifyRequest(options, content)).resolves.toEqual('Successfully delivered'); + await expect(notification.notifyRequest(options, content)).resolves.toEqual( + 'Successfully delivered' + ); expect(logger.logger.info).toHaveBeenCalledWith(...infoArgs); expect(logger.logger.debug).toHaveBeenCalledWith(...debugArgs); }); @@ -83,7 +91,7 @@ describe('Notifications:: notifyRequest', () => { test('when notification is successfully delivered but body is undefined/null', async () => { jest.doMock('request', () => (options, resolver) => { const response = { - statusCode: HTTP_STATUS.OK, + statusCode: HTTP_STATUS.OK }; resolver(null, response); diff --git a/test/unit/modules/plugin/auth.spec.ts b/test/unit/modules/plugin/auth.spec.ts index 7ae7082da..26fb474b5 100644 --- a/test/unit/modules/plugin/auth.spec.ts +++ b/test/unit/modules/plugin/auth.spec.ts @@ -2,10 +2,10 @@ import _ from 'lodash'; import Auth from '../../../../src/lib/auth'; import { authProfileConf, authPluginFailureConf, authPluginPassThrougConf } from './helper/plugin'; import AppConfig from '../../../../src/lib/config'; -import {setup} from '../../../../src/lib/logger'; +import { setup } from '../../../../src/lib/logger'; -import {IAuth} from '../../../../types'; -import {Config} from '@verdaccio/types'; +import { IAuth } from '../../../../types'; +import { Config } from '@verdaccio/types'; import { ROLES } from '../../../../src/lib/constants'; import { getInternalError } from '@verdaccio/commons-api'; @@ -28,18 +28,23 @@ describe('AuthTest', () => { expect(auth).toBeDefined(); const callback = jest.fn(); - const groups = [ "test" ]; + const groups = ['test']; auth.authenticate('foo', 'bar', callback); expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith(null, - {"groups": - [ - "test", ROLES.$ALL, ROLES.$AUTH, ROLES.DEPRECATED_ALL, ROLES.DEPRECATED_AUTH, ROLES.ALL], - "name": 'foo', - "real_groups": groups - }); + expect(callback).toHaveBeenCalledWith(null, { + groups: [ + 'test', + ROLES.$ALL, + ROLES.$AUTH, + ROLES.DEPRECATED_ALL, + ROLES.DEPRECATED_AUTH, + ROLES.ALL + ], + name: 'foo', + real_groups: groups + }); }); test('should be a fail on login', () => { @@ -70,7 +75,7 @@ describe('AuthTest', () => { let index = 0; // as defined by https://developer.mozilla.org/en-US/docs/Glossary/Falsy - for (const value of [ false, 0, "", null, undefined, NaN ]) { + for (const value of [false, 0, '', null, undefined, NaN]) { // @ts-ignore auth.authenticate(null, value, callback); const call = callback.mock.calls[index++]; @@ -87,8 +92,8 @@ describe('AuthTest', () => { const callback = jest.fn(); - for (const value of [ true, 1, "test", { } ]) { - expect(function ( ) { + for (const value of [true, 1, 'test', {}]) { + expect(function () { // @ts-ignore auth.authenticate(null, value, callback); }).toThrow(TypeError); @@ -103,7 +108,7 @@ describe('AuthTest', () => { expect(auth).toBeDefined(); const callback = jest.fn(); - const value = [ ]; + const value = []; // @ts-ignore auth.authenticate(null, value, callback); @@ -121,7 +126,7 @@ describe('AuthTest', () => { const callback = jest.fn(); let index = 0; - for (const value of [ [ "" ], [ "1" ], [ "0" ], ["000"] ]) { + for (const value of [[''], ['1'], ['0'], ['000']]) { // @ts-ignore auth.authenticate(null, value, callback); const call = callback.mock.calls[index++]; @@ -130,5 +135,5 @@ describe('AuthTest', () => { } }); }); - }) + }); }); diff --git a/test/unit/modules/plugin/helper/plugin.ts b/test/unit/modules/plugin/helper/plugin.ts index f6f8ccd60..d16fb9e06 100644 --- a/test/unit/modules/plugin/helper/plugin.ts +++ b/test/unit/modules/plugin/helper/plugin.ts @@ -3,18 +3,18 @@ import config from '../../../partials/config'; export const authProfileConf = config({ auth: { - [`${path.join(__dirname, '../../../partials/plugin/authenticate.success')}`]: { } + [`${path.join(__dirname, '../../../partials/plugin/authenticate.success')}`]: {} } }); export const authPluginFailureConf = config({ auth: { - [`${path.join(__dirname, '../../../partials/plugin/authenticate.fail')}`]: { } + [`${path.join(__dirname, '../../../partials/plugin/authenticate.fail')}`]: {} } }); export const authPluginPassThrougConf = config({ auth: { - [`${path.join(__dirname, '../../../partials/plugin/authenticate.passthroug')}`]: { } + [`${path.join(__dirname, '../../../partials/plugin/authenticate.passthroug')}`]: {} } }); diff --git a/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/.eslintrc b/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/.eslintrc new file mode 100644 index 000000000..8ec0114bb --- /dev/null +++ b/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "max-len": "off" + } +} diff --git a/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/dummy.js b/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/dummy.js index e002568cc..5346f1fe6 100644 --- a/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/dummy.js +++ b/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/dummy.js @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) {descriptor.writable = true;} Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) {defineProperties(Constructor.prototype, protoProps);} if (staticProps) {defineProperties(Constructor, staticProps);} return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } diff --git a/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/index.js b/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/index.js index a01985c72..3630aabb2 100644 --- a/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/index.js +++ b/test/unit/modules/plugin/partials/test-plugin-storage/verdaccio-es6-plugin/index.js @@ -13,4 +13,4 @@ var _dummy2 = _interopRequireDefault(_dummy); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.Dummy = _dummy2.default; -exports.default = _dummy2.default; \ No newline at end of file +exports.default = _dummy2.default; diff --git a/test/unit/modules/plugin/plugin_loader.spec.ts b/test/unit/modules/plugin/plugin_loader.spec.ts index 72da9d200..8a1ec6026 100644 --- a/test/unit/modules/plugin/plugin_loader.spec.ts +++ b/test/unit/modules/plugin/plugin_loader.spec.ts @@ -1,12 +1,12 @@ import path from 'path'; import loadPlugin from '../../../../src/lib/plugin-loader'; -import { setup } from '../../../../src/lib/logger'; +import { setup } from '../../../../src/lib/logger'; setup([]); describe('plugin loader', () => { const relativePath = path.join(__dirname, './partials/test-plugin-storage'); - const buildConf = name => { + const buildConf = (name) => { return { self_path: path.join(__dirname, './'), max_users: 0, @@ -44,8 +44,10 @@ describe('plugin loader', () => { loadPlugin(_config, _config.auth, {}, function (p) { return p.authenticate || p.allow_access || p.allow_publish; }); - } catch(e) { - expect(e.message).toEqual(`"${relativePath}/invalid-plugin" plugin does not have the right code structure`); + } catch (e) { + expect(e.message).toEqual( + `"${relativePath}/invalid-plugin" plugin does not have the right code structure` + ); } }); @@ -56,8 +58,10 @@ describe('plugin loader', () => { loadPlugin(_config, _config.auth, {}, function (plugin) { return plugin.authenticate || plugin.allow_access || plugin.allow_publish; }); - } catch(err) { - expect(err.message).toEqual(`sanity check has failed, "${relativePath}/invalid-plugin-sanity" is not a valid plugin`); + } catch (err) { + expect(err.message).toEqual( + `sanity check has failed, "${relativePath}/invalid-plugin-sanity" is not a valid plugin` + ); } }); @@ -68,7 +72,7 @@ describe('plugin loader', () => { loadPlugin(_config, _config.auth, {}, function (plugin) { return plugin.authenticate || plugin.allow_access || plugin.allow_publish; }); - } catch(e) { + } catch (e) { expect(e.message).toMatch('plugin not found'); expect(e.message).toMatch('/partials/test-plugin-storage/invalid-package'); } @@ -77,5 +81,4 @@ describe('plugin loader', () => { test.todo('test middleware plugins'); test.todo('test storage plugins'); }); - }); diff --git a/test/unit/modules/search/search.spec.ts b/test/unit/modules/search/search.spec.ts index affd08e1d..81a454dd8 100644 --- a/test/unit/modules/search/search.spec.ts +++ b/test/unit/modules/search/search.spec.ts @@ -11,32 +11,32 @@ let packages = [ name: 'test1', description: 'description', _npmUser: { - name: 'test_user', - }, + name: 'test_user' + } }, { name: 'test2', description: 'description', _npmUser: { - name: 'test_user', - }, + name: 'test_user' + } }, { name: 'test3', description: 'description', _npmUser: { - name: 'test_user', - }, - }, + name: 'test_user' + } + } ]; describe('search', () => { - beforeAll(async function() { + beforeAll(async function () { let config = new Config(buildConfig()); const storage = new Storage(config); await storage.init(config); Search.configureStorage(storage); - packages.map(function(item) { + packages.map(function (item) { // @ts-ignore Search.add(item); }); @@ -52,8 +52,8 @@ describe('search', () => { name: 'test6', description: 'description', _npmUser: { - name: 'test_user', - }, + name: 'test_user' + } }; // @ts-ignore Search.add(item); diff --git a/test/unit/modules/storage/local-storage.spec.ts b/test/unit/modules/storage/local-storage.spec.ts index 359b38bfb..b11a362d5 100644 --- a/test/unit/modules/storage/local-storage.spec.ts +++ b/test/unit/modules/storage/local-storage.spec.ts @@ -5,16 +5,17 @@ import LocalStorage from '../../../../src/lib/local-storage'; import AppConfig from '../../../../src/lib/config'; // @ts-ignore import configExample from '../../partials/config'; -import { logger, setup} from '../../../../src/lib/logger'; -import {readFile} from '../../../functional/lib/test.utils'; -import {generatePackageTemplate} from '../../../../src/lib/storage-utils'; -import {generateNewVersion} from '../../../lib/utils-test'; +import { logger, setup } from '../../../../src/lib/logger'; +import { readFile } from '../../../functional/lib/test.utils'; +import { generatePackageTemplate } from '../../../../src/lib/storage-utils'; +import { generateNewVersion } from '../../../lib/utils-test'; -const readMetadata = (fileName = 'metadata') => readFile(`../../unit/partials/${fileName}`).toString(); +const readMetadata = (fileName = 'metadata') => + readFile(`../../unit/partials/${fileName}`).toString(); -import {Config, MergeTags, Package} from '@verdaccio/types'; -import {IStorage} from '../../../../types'; -import { API_ERROR, HTTP_STATUS, DIST_TAGS} from '../../../../src/lib/constants'; +import { Config, MergeTags, Package } from '@verdaccio/types'; +import { IStorage } from '../../../../types'; +import { API_ERROR, HTTP_STATUS, DIST_TAGS } from '../../../../src/lib/constants'; import { VerdaccioError } from '@verdaccio/commons-api'; setup([]); @@ -27,16 +28,18 @@ describe('LocalStorage', () => { const tarballName2 = `${pkgName}-add-tarball-1.0.5.tgz`; const getStorage = (LocalStorageClass = LocalStorage) => { - const config: Config = new AppConfig(configExample({ - self_path: path.join('../partials/store') - })); + const config: Config = new AppConfig( + configExample({ + self_path: path.join('../partials/store') + }) + ); return new LocalStorageClass(config, logger); - } + }; const getPackageMetadataFromStore = (pkgName: string): Promise => { return new Promise((resolve) => { - storage.getPackageMetadata(pkgName, (err, data ) => { + storage.getPackageMetadata(pkgName, (err, data) => { resolve(data); }); }); @@ -44,9 +47,15 @@ describe('LocalStorage', () => { const addNewVersion = (pkgName: string, version: string) => { return new Promise((resolve) => { - storage.addVersion(pkgName, version, generateNewVersion(pkgName, version), '', (err, data) => { - resolve(data); - }); + storage.addVersion( + pkgName, + version, + generateNewVersion(pkgName, version), + '', + (err, data) => { + resolve(data); + } + ); }); }; const addTarballToStore = (pkgName: string, tarballName) => { @@ -203,11 +212,17 @@ describe('LocalStorage', () => { await addTarballToStore(pkgName, `${pkgName}-9.0.0.tgz`); await addTarballToStore(pkgName, tarballName); - storage.addVersion(pkgName, version, generateNewVersion(pkgName, version), '', (err, data) => { - expect(err).toBeNull(); - expect(data).toBeUndefined(); - done(); - }); + storage.addVersion( + pkgName, + version, + generateNewVersion(pkgName, version), + '', + (err, data) => { + expect(err).toBeNull(); + expect(data).toBeUndefined(); + done(); + } + ); }); test('should fails on add a duplicated version without tag', async (done) => { @@ -216,7 +231,7 @@ describe('LocalStorage', () => { await addPackageToStore(pkgName, generatePackageTemplate(pkgName)); await addNewVersion(pkgName, version); - storage.addVersion(pkgName, version, generateNewVersion(pkgName, version), '', err => { + storage.addVersion(pkgName, version, generateNewVersion(pkgName, version), '', (err) => { expect(err).not.toBeNull(); expect(err.statusCode).toEqual(HTTP_STATUS.CONFLICT); expect(err.message).toMatch(API_ERROR.PACKAGE_EXIST); @@ -231,12 +246,18 @@ describe('LocalStorage', () => { const tarballName = `${pkgName}-${version}.tgz`; await addTarballToStore(pkgName, tarballName); - storage.addVersion(pkgName, version, generateNewVersion(pkgName, version, 'fake'), '', err => { - expect(err).not.toBeNull(); - expect(err.statusCode).toEqual(HTTP_STATUS.BAD_REQUEST); - expect(err.message).toMatch(/shasum error/); - done(); - }); + storage.addVersion( + pkgName, + version, + generateNewVersion(pkgName, version, 'fake'), + '', + (err) => { + expect(err).not.toBeNull(); + expect(err.statusCode).toEqual(HTTP_STATUS.BAD_REQUEST); + expect(err.message).toMatch(/shasum error/); + done(); + } + ); }); test('should add new second version without tag', async (done) => { @@ -246,11 +267,17 @@ describe('LocalStorage', () => { await addNewVersion(pkgName, '1.0.1'); await addNewVersion(pkgName, '1.0.3'); - storage.addVersion(pkgName, version, generateNewVersion(pkgName, version), 'beta', (err, data) => { - expect(err).toBeNull(); - expect(data).toBeUndefined(); - done(); - }); + storage.addVersion( + pkgName, + version, + generateNewVersion(pkgName, version), + 'beta', + (err, data) => { + expect(err).toBeNull(); + expect(data).toBeUndefined(); + done(); + } + ); }); }); @@ -259,18 +286,18 @@ describe('LocalStorage', () => { const pkgName = 'add-update-versions-test-1'; const version = '1.0.2'; let _storage; - beforeEach(done => { + beforeEach((done) => { class MockLocalStorage extends LocalStorage {} // @ts-ignore - MockLocalStorage.prototype._writePackage = jest.fn(LocalStorage.prototype._writePackage) + MockLocalStorage.prototype._writePackage = jest.fn(LocalStorage.prototype._writePackage); _storage = getStorage(MockLocalStorage); rimRaf(path.join(configExample().storage, pkgName), async () => { await addPackageToStore(pkgName, generatePackageTemplate(pkgName)); await addNewVersion(pkgName, '1.0.1'); await addNewVersion(pkgName, version); done(); - }) - }) + }); + }); test('should update versions from external source', async (done) => { _storage.updateVersions(pkgName, metadata, (err, data) => { @@ -291,22 +318,22 @@ describe('LocalStorage', () => { }); }); - test('should not update if the metadata match', done => { - _storage.updateVersions(pkgName, metadata, e => { - expect(e).toBeNull() - _storage.updateVersions(pkgName, metadata, err => { - expect(err).toBeNull() + test('should not update if the metadata match', (done) => { + _storage.updateVersions(pkgName, metadata, (e) => { + expect(e).toBeNull(); + _storage.updateVersions(pkgName, metadata, (err) => { + expect(err).toBeNull(); expect(_storage._writePackage).toHaveBeenCalledTimes(1); - done() - }) - }) - }) + done(); + }); + }); + }); }); describe('LocalStorage::changePackage', () => { const pkgName = 'change-package'; - test('should unpublish a version', async done => { + test('should unpublish a version', async (done) => { await addPackageToStore(pkgName, generatePackageTemplate(pkgName)); await addNewVersion(pkgName, '1.0.1'); await addNewVersion(pkgName, '1.0.2'); @@ -316,7 +343,7 @@ describe('LocalStorage', () => { storage.changePackage(pkgName, metadata, rev, (err) => { expect(err).toBeUndefined(); - storage.getPackageMetadata(pkgName, (err, data ) => { + storage.getPackageMetadata(pkgName, (err, data) => { expect(err).toBeNull(); expect(data.versions['1.0.1']).toBeDefined(); expect(data.versions['1.0.2']).toBeUndefined(); @@ -328,9 +355,7 @@ describe('LocalStorage', () => { }); describe('LocalStorage::tarball operations', () => { - describe('LocalStorage::addTarball', () => { - test('should add a new tarball', (done) => { const tarballData = JSON.parse(readMetadata('addTarball')); const stream = storage.addTarball(pkgName, tarballName); @@ -339,7 +364,7 @@ describe('LocalStorage', () => { expect(err).toBeNull(); done(); }); - stream.on('success', function() { + stream.on('success', function () { done(); }); @@ -354,7 +379,7 @@ describe('LocalStorage', () => { expect(err).toBeNull(); done(); }); - stream.on('success', function() { + stream.on('success', function () { done(); }); @@ -362,7 +387,7 @@ describe('LocalStorage', () => { stream.done(); }); - test('should fails on add a duplicated new tarball ', (done) => { + test('should fails on add a duplicated new tarball', (done) => { const tarballData = JSON.parse(readMetadata('addTarball')); const stream = storage.addTarball(pkgName, tarballName); stream.on('error', (err: VerdaccioError) => { @@ -395,7 +420,7 @@ describe('LocalStorage', () => { test('should fails on use invalid package name on add a new tarball', (done) => { const stream = storage.addTarball(pkgName, `${pkgName}-fails-add-tarball-1.0.4.tgz`); - stream.on('error', function(err: VerdaccioError) { + stream.on('error', function (err: VerdaccioError) { expect(err).not.toBeNull(); expect(err.statusCode).toEqual(HTTP_STATUS.BAD_DATA); expect(err.message).toMatch(/refusing to accept zero-length file/); @@ -408,7 +433,7 @@ describe('LocalStorage', () => { test('should fails on abort on add a new tarball', (done) => { const stream = storage.addTarball('__proto__', `${pkgName}-fails-add-tarball-1.0.4.tgz`); stream.abort(); - stream.on('error', function(err: VerdaccioError) { + stream.on('error', function (err: VerdaccioError) { expect(err).not.toBeNull(); expect(err.statusCode).toEqual(HTTP_STATUS.FORBIDDEN); expect(err.message).toMatch(/can't use this filename/); @@ -417,10 +442,8 @@ describe('LocalStorage', () => { stream.done(); }); - }); describe('LocalStorage::removeTarball', () => { - test('should remove a tarball', (done) => { storage.removeTarball(pkgName, tarballName2, 'rev', (err, pkg) => { expect(err).toBeNull(); @@ -442,18 +465,18 @@ describe('LocalStorage', () => { describe('LocalStorage::getTarball', () => { test('should get a existing tarball', (done) => { const stream = storage.getTarball(pkgName, tarballName); - stream.on('content-length', function(contentLength) { + stream.on('content-length', function (contentLength) { expect(contentLength).toBe(279); done(); }); - stream.on('open', function() { + stream.on('open', function () { done(); }); }); test('should fails on get a tarball that does not exist', (done) => { const stream = storage.getTarball('fake', tarballName); - stream.on('error', function(err: VerdaccioError) { + stream.on('error', function (err: VerdaccioError) { expect(err).not.toBeNull(); expect(err.statusCode).toEqual(HTTP_STATUS.NOT_FOUND); expect(err.message).toMatch(/no such file available/); @@ -471,16 +494,15 @@ describe('LocalStorage', () => { expect(pkg.name).toEqual(pkgName); }); - stream.on('error', function(err) { + stream.on('error', function (err) { expect(err).not.toBeNull(); done(); }); - stream.on('end', function() { + stream.on('end', function () { done(); }); }); - }); }); @@ -503,7 +525,7 @@ describe('LocalStorage', () => { test('should fails with package not found', (done) => { const pkgName = 'npm_test_fake'; - storage.removePackage(pkgName, err => { + storage.removePackage(pkgName, (err) => { expect(err).not.toBeNull(); expect(err.message).toMatch(/no such package available/); done(); @@ -511,7 +533,7 @@ describe('LocalStorage', () => { }); test('should fails with @scoped package not found', (done) => { - storage.removePackage(pkgNameScoped, err => { + storage.removePackage(pkgNameScoped, (err) => { expect(err).not.toBeNull(); expect(err.message).toMatch(API_ERROR.NO_PACKAGE); done(); @@ -519,5 +541,4 @@ describe('LocalStorage', () => { }); }); }); - }); diff --git a/test/unit/modules/storage/merge.dist.tags.spec.ts b/test/unit/modules/storage/merge.dist.tags.spec.ts index bad5b63e6..3ef5ff711 100644 --- a/test/unit/modules/storage/merge.dist.tags.spec.ts +++ b/test/unit/modules/storage/merge.dist.tags.spec.ts @@ -1,73 +1,66 @@ import assert from 'assert'; let semverSort = require('../../../../src/lib/utils').semverSort; -import {mergeVersions} from '../../../../src/lib/metadata-utils'; +import { mergeVersions } from '../../../../src/lib/metadata-utils'; require('../../../../src/lib/logger').setup([]); describe('Storage._merge_versions versions', () => { - test('simple', () => { let pkg = { - 'versions': {a: 1, b: 1, c: 1}, - 'dist-tags': {}, + versions: { a: 1, b: 1, c: 1 }, + 'dist-tags': {} }; // @ts-ignore - mergeVersions(pkg, {versions: {a: 2, q: 2}}); + mergeVersions(pkg, { versions: { a: 2, q: 2 } }); assert.deepEqual(pkg, { - 'versions': {a: 1, b: 1, c: 1, q: 2}, - 'dist-tags': {}, + versions: { a: 1, b: 1, c: 1, q: 2 }, + 'dist-tags': {} }); }); test('dist-tags - compat', () => { let pkg = { - 'versions': {}, - 'dist-tags': {q: '1.1.1', w: '2.2.2'}, + versions: {}, + 'dist-tags': { q: '1.1.1', w: '2.2.2' } }; // @ts-ignore - mergeVersions(pkg, {'dist-tags': {q: '2.2.2', w: '3.3.3', t: '4.4.4'}}); + mergeVersions(pkg, { 'dist-tags': { q: '2.2.2', w: '3.3.3', t: '4.4.4' } }); assert.deepEqual(pkg, { - 'versions': {}, - 'dist-tags': {q: '2.2.2', w: '3.3.3', t: '4.4.4'}, + versions: {}, + 'dist-tags': { q: '2.2.2', w: '3.3.3', t: '4.4.4' } }); }); test('dist-tags - staging', () => { - let pkg = { versions: {}, // we've been locally publishing 1.1.x in preparation for the next // public release - 'dist-tags': {q:'1.1.10',w:'2.2.2'}, + 'dist-tags': { q: '1.1.10', w: '2.2.2' } }; // 1.1.2 is the latest public release, but we want to continue testing // against our local 1.1.10, which may end up published as 1.1.3 in the // future // @ts-ignore - mergeVersions(pkg, {'dist-tags':{q:'1.1.2',w:'3.3.3',t:'4.4.4'}}) + mergeVersions(pkg, { 'dist-tags': { q: '1.1.2', w: '3.3.3', t: '4.4.4' } }); assert.deepEqual(pkg, { versions: {}, - 'dist-tags': {q:'1.1.10',w:'3.3.3',t:'4.4.4'}, + 'dist-tags': { q: '1.1.10', w: '3.3.3', t: '4.4.4' } }); - }); test('semverSort', () => { - - assert.deepEqual(semverSort(['1.2.3', '1.2', '1.2.3a', '1.2.3c', '1.2.3-b']), - ['1.2.3a', - '1.2.3-b', - '1.2.3c', - '1.2.3'] - ); - + assert.deepEqual(semverSort(['1.2.3', '1.2', '1.2.3a', '1.2.3c', '1.2.3-b']), [ + '1.2.3a', + '1.2.3-b', + '1.2.3c', + '1.2.3' + ]); }); - }); - diff --git a/test/unit/modules/storage/storage-utils.spec.ts b/test/unit/modules/storage/storage-utils.spec.ts index 9ae672b0a..27e4534f7 100644 --- a/test/unit/modules/storage/storage-utils.spec.ts +++ b/test/unit/modules/storage/storage-utils.spec.ts @@ -1,8 +1,8 @@ -import {normalizePackage, mergeUplinkTimeIntoLocal} from "../../../../src/lib/storage-utils"; +import { normalizePackage, mergeUplinkTimeIntoLocal } from '../../../../src/lib/storage-utils'; import { STORAGE, DIST_TAGS } from '../../../../src/lib/constants'; -import {readFile} from "../../../functional/lib/test.utils"; +import { readFile } from '../../../functional/lib/test.utils'; -import {Package} from '@verdaccio/types'; +import { Package } from '@verdaccio/types'; const readMetadata = (fileName = 'metadata') => readFile(`../../unit/partials/${fileName}`); @@ -16,7 +16,7 @@ describe('Storage Utils', () => { _uplinks: {}, name: '', versions: {}, - [DIST_TAGS]: {}, + [DIST_TAGS]: {} }); expect(pkg).toBeDefined(); expect(pkg.time).toBeInstanceOf(Object); @@ -50,13 +50,13 @@ describe('Storage Utils', () => { describe('mergeTime', () => { const vGroup1 = { - "1.0.15": "2018-06-12T23:15:05.864Z", - "1.0.16": "2018-06-12T23:17:46.578Z", - "1.0.17": "2018-06-12T23:20:59.106Z" + '1.0.15': '2018-06-12T23:15:05.864Z', + '1.0.16': '2018-06-12T23:17:46.578Z', + '1.0.17': '2018-06-12T23:20:59.106Z' }; const vGroup2 = { - "1.0.6": "2018-06-07T05:50:21.505Z", - "1.0.7": "2018-06-12T20:35:07.621Z" + '1.0.6': '2018-06-07T05:50:21.505Z', + '1.0.7': '2018-06-12T20:35:07.621Z' }; test('mergeTime basic', () => { const pkg1: Package = { @@ -65,13 +65,13 @@ describe('Storage Utils', () => { _rev: '', _uplinks: {}, time: { - "modified": "2018-06-13T06:44:45.747Z", - "created": "2018-06-07T05:50:21.505Z", + modified: '2018-06-13T06:44:45.747Z', + created: '2018-06-07T05:50:21.505Z', ...vGroup1 }, name: '', versions: {}, - [DIST_TAGS]: {}, + [DIST_TAGS]: {} }; const pkg2: Package = { @@ -81,17 +81,21 @@ describe('Storage Utils', () => { _uplinks: {}, name: '', time: { - "modified": "2019-06-13T06:44:45.747Z", - "created": "2019-06-07T05:50:21.505Z", + modified: '2019-06-13T06:44:45.747Z', + created: '2019-06-07T05:50:21.505Z', ...vGroup2 }, versions: {}, - [DIST_TAGS]: {}, + [DIST_TAGS]: {} }; const mergedPkg = mergeUplinkTimeIntoLocal(pkg1, pkg2); - expect(Object.keys(mergedPkg)).toEqual(["modified", "created", - ...Object.keys(vGroup1), ...Object.keys(vGroup2)]); + expect(Object.keys(mergedPkg)).toEqual([ + 'modified', + 'created', + ...Object.keys(vGroup1), + ...Object.keys(vGroup2) + ]); }); test('mergeTime remote empty', () => { @@ -102,12 +106,12 @@ describe('Storage Utils', () => { _uplinks: {}, name: '', time: { - "modified": "2018-06-13T06:44:45.747Z", - "created": "2018-06-07T05:50:21.505Z", + modified: '2018-06-13T06:44:45.747Z', + created: '2018-06-07T05:50:21.505Z', ...vGroup1 }, versions: {}, - [DIST_TAGS]: {}, + [DIST_TAGS]: {} }; const pkg2: Package = { @@ -117,10 +121,10 @@ describe('Storage Utils', () => { _uplinks: {}, name: '', versions: {}, - [DIST_TAGS]: {}, + [DIST_TAGS]: {} }; const mergedPkg = mergeUplinkTimeIntoLocal(pkg1, pkg2); - expect(Object.keys(mergedPkg)).toEqual(["modified", "created", ...Object.keys(vGroup1)]); + expect(Object.keys(mergedPkg)).toEqual(['modified', 'created', ...Object.keys(vGroup1)]); }); }); }); diff --git a/test/unit/modules/storage/store.spec.ts b/test/unit/modules/storage/store.spec.ts index a8480a13e..20ab3a762 100644 --- a/test/unit/modules/storage/store.spec.ts +++ b/test/unit/modules/storage/store.spec.ts @@ -1,92 +1,99 @@ import path from 'path'; import fs from 'fs'; import rimraf from 'rimraf'; -import {Writable} from 'stream'; +import { Writable } from 'stream'; import configExample from '../../partials/config'; import AppConfig from '../../../../src/lib/config'; import Storage from '../../../../src/lib/storage'; -import {setup} from '../../../../src/lib/logger'; +import { setup } from '../../../../src/lib/logger'; -import {Config} from '@verdaccio/types'; -import {IStorageHandler} from '../../../../types'; -import {API_ERROR, HTTP_STATUS} from '../../../../src/lib/constants'; -import {mockServer} from '../../__helper/mock'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; +import { Config } from '@verdaccio/types'; +import { IStorageHandler } from '../../../../types'; +import { API_ERROR, HTTP_STATUS } from '../../../../src/lib/constants'; +import { mockServer } from '../../__helper/mock'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; setup([]); const storagePath = path.join(__dirname, '../../partials/store/test-storage-store.spec'); const mockServerPort = 55548; -const generateStorage = async function(port = mockServerPort) { - const storageConfig = configExample({ - self_path: __dirname, - storage: storagePath, - uplinks: { - npmjs: { - url: `http://${DOMAIN_SERVERS}:${port}` - } - } - }, 'store.spec.yaml'); - - const config: Config = new AppConfig(storageConfig); - const store: IStorageHandler = new Storage(config); - await store.init(config, []); - - return store; -} - -const generateSameUplinkStorage = async function(port = mockServerPort) { - const storageConfig = configExample({ - self_path: __dirname, - storage: storagePath, - packages: { - jquery: { - access: ['$all'], - publish: ['$all'], - proxy: ['cached'], - }, - '@jquery/*': { - access: ['$all'], - publish: ['$all'], - proxy: ['notcached'], +const generateStorage = async function (port = mockServerPort) { + const storageConfig = configExample( + { + self_path: __dirname, + storage: storagePath, + uplinks: { + npmjs: { + url: `http://${DOMAIN_SERVERS}:${port}` + } } }, - uplinks: { - cached: { - url: `http://${DOMAIN_SERVERS}:${port}`, - cache: true, - }, - notcached: { - url: `http://${DOMAIN_SERVERS}:${port}`, - cache: false, - } - } - }, 'store.spec.yaml'); + 'store.spec.yaml' + ); const config: Config = new AppConfig(storageConfig); const store: IStorageHandler = new Storage(config); await store.init(config, []); return store; -} +}; -const createNullStream = () => new Writable({ - write: function(chunk, encoding, next) { - next(); - } -}); +const generateSameUplinkStorage = async function (port = mockServerPort) { + const storageConfig = configExample( + { + self_path: __dirname, + storage: storagePath, + packages: { + jquery: { + access: ['$all'], + publish: ['$all'], + proxy: ['cached'] + }, + '@jquery/*': { + access: ['$all'], + publish: ['$all'], + proxy: ['notcached'] + } + }, + uplinks: { + cached: { + url: `http://${DOMAIN_SERVERS}:${port}`, + cache: true + }, + notcached: { + url: `http://${DOMAIN_SERVERS}:${port}`, + cache: false + } + } + }, + 'store.spec.yaml' + ); + + const config: Config = new AppConfig(storageConfig); + const store: IStorageHandler = new Storage(config); + await store.init(config, []); + + return store; +}; + +const createNullStream = () => + new Writable({ + write: function (chunk, encoding, next) { + next(); + } + }); describe('StorageTest', () => { let mockRegistry; - beforeAll(done => { + beforeAll((done) => { rimraf(storagePath, async () => { mockRegistry = await mockServer(mockServerPort).init(); - done() - }) + done(); + }); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); @@ -126,7 +133,9 @@ describe('StorageTest', () => { reader.on('end', () => { expect(cachedSpy).toHaveBeenCalledTimes(0); expect(notcachedSpy).toHaveBeenCalledTimes(1); - expect(notcachedSpy).toHaveBeenCalledWith('http://0.0.0.0:55548/@jquery%2fjquery/-/jquery-1.5.1.tgz'); + expect(notcachedSpy).toHaveBeenCalledWith( + 'http://0.0.0.0:55548/@jquery%2fjquery/-/jquery-1.5.1.tgz' + ); res(); }); reader.on('error', (err) => { @@ -179,7 +188,7 @@ describe('StorageTest', () => { }); test('should not touch if the package exists and has no uplinks', async (done) => { - const storage: IStorageHandler = await generateStorage() as IStorageHandler; + const storage: IStorageHandler = (await generateStorage()) as IStorageHandler; const metadataSource = path.join(__dirname, '../../partials/metadata'); const metadataPath = path.join(storagePath, 'npm_test/package.json'); diff --git a/test/unit/modules/uplinks/headers.auth.spec.ts b/test/unit/modules/uplinks/headers.auth.spec.ts index fadffbc45..7efd6feaa 100644 --- a/test/unit/modules/uplinks/headers.auth.spec.ts +++ b/test/unit/modules/uplinks/headers.auth.spec.ts @@ -1,7 +1,13 @@ import ProxyStorage from '../../../../src/lib/up-storage'; -import {ERROR_CODE, TOKEN_BASIC, TOKEN_BEARER, DEFAULT_REGISTRY, HEADERS} from "../../../../src/lib/constants"; -import {buildToken} from "../../../../src/lib/utils"; -import {setup} from '../../../../src/lib/logger'; +import { + ERROR_CODE, + TOKEN_BASIC, + TOKEN_BEARER, + DEFAULT_REGISTRY, + HEADERS +} from '../../../../src/lib/constants'; +import { buildToken } from '../../../../src/lib/utils'; +import { setup } from '../../../../src/lib/logger'; setup([]); @@ -23,7 +29,6 @@ function setHeaders(config: unknown = {}, headers: unknown = {}) { } describe('uplink headers auth test', () => { - test('if set headers empty should return default headers', () => { const headers = setHeaders(); const keys = Object.keys(headers); @@ -40,35 +45,38 @@ describe('uplink headers auth test', () => { }); }; - expect(function ( ) { + expect(function () { fnError(); }).toThrow(Error('Auth invalid')); }); test('if assigns the header authorization', () => { - const headers = setHeaders({}, { - [HEADERS.AUTHORIZATION]: buildToken(TOKEN_BASIC, 'Zm9vX2Jhcg==') - }); + const headers = setHeaders( + {}, + { + [HEADERS.AUTHORIZATION]: buildToken(TOKEN_BASIC, 'Zm9vX2Jhcg==') + } + ); expect(Object.keys(headers)).toHaveLength(4); expect(headers[HEADERS.AUTHORIZATION]).toEqual(buildToken(TOKEN_BASIC, 'Zm9vX2Jhcg==')); }); - test( - 'if assigns headers authorization and token the header precedes', - () => { - const headers = setHeaders({ + test('if assigns headers authorization and token the header precedes', () => { + const headers = setHeaders( + { auth: { type: TOKEN_BEARER, token: 'tokenBearer' } - }, { + }, + { [HEADERS.AUTHORIZATION]: buildToken(TOKEN_BASIC, 'tokenBasic') - }); + } + ); - expect(headers[HEADERS.AUTHORIZATION]).toEqual(buildToken(TOKEN_BASIC, 'tokenBasic')); - } - ); + expect(headers[HEADERS.AUTHORIZATION]).toEqual(buildToken(TOKEN_BASIC, 'tokenBasic')); + }); test('set type auth basic', () => { const headers = setHeaders({ @@ -95,16 +103,16 @@ describe('uplink headers auth test', () => { }); test('set auth type invalid', () => { - const fnError = function() { + const fnError = function () { setHeaders({ auth: { type: 'null', token: 'Zm9vX2Jhcf===' } - }) + }); }; - expect(function ( ) { + expect(function () { fnError(); }).toThrow(Error(`Auth type 'null' not allowed`)); }); @@ -134,9 +142,8 @@ describe('uplink headers auth test', () => { delete process.env.NPM_TOKEN_TEST; }); - test('if token not set', () => { - const fnError = function() { + const fnError = function () { setHeaders({ auth: { type: TOKEN_BASIC @@ -144,7 +151,7 @@ describe('uplink headers auth test', () => { }); }; - expect(function( ) { + expect(function () { fnError(); }).toThrow(ERROR_CODE.token_required); }); diff --git a/test/unit/modules/uplinks/noProxy.spec.ts b/test/unit/modules/uplinks/noProxy.spec.ts index 434f5d599..8f5a38d04 100644 --- a/test/unit/modules/uplinks/noProxy.spec.ts +++ b/test/unit/modules/uplinks/noProxy.spec.ts @@ -16,81 +16,81 @@ describe('Use proxy', () => { }); test('local config should take priority', () => { - let x = setupProxy('http://x/x', {http_proxy: '123'}, {http_proxy: '456'}); + let x = setupProxy('http://x/x', { http_proxy: '123' }, { http_proxy: '456' }); expect(x.proxy).toEqual('123'); }); test('no_proxy is invalid', () => { - let x = setupProxy('http://x/x', {http_proxy: '123', no_proxy: false}, {}); + let x = setupProxy('http://x/x', { http_proxy: '123', no_proxy: false }, {}); expect(x.proxy).toEqual('123'); - x = setupProxy('http://x/x', {http_proxy: '123', no_proxy: null}, {}); + x = setupProxy('http://x/x', { http_proxy: '123', no_proxy: null }, {}); expect(x.proxy).toEqual('123'); - x = setupProxy('http://x/x', {http_proxy: '123', no_proxy: []}, {}); + x = setupProxy('http://x/x', { http_proxy: '123', no_proxy: [] }, {}); expect(x.proxy).toEqual('123'); - x = setupProxy('http://x/x', {http_proxy: '123', no_proxy: ''}, {}); + x = setupProxy('http://x/x', { http_proxy: '123', no_proxy: '' }, {}); expect(x.proxy).toEqual('123'); }); test('no_proxy - simple/include', () => { - let x = setupProxy('http://localhost', {http_proxy: '123'}, {no_proxy: 'localhost'}); + let x = setupProxy('http://localhost', { http_proxy: '123' }, { no_proxy: 'localhost' }); expect(x.proxy).toEqual(undefined); }); test('no_proxy - simple/not', () => { - let x = setupProxy('http://localhost', {http_proxy: '123'}, {no_proxy: 'blah'}); + let x = setupProxy('http://localhost', { http_proxy: '123' }, { no_proxy: 'blah' }); expect(x.proxy).toEqual('123'); }); test('no_proxy - various, single string', () => { - let x = setupProxy('http://blahblah', {http_proxy: '123'}, {no_proxy: 'blah'}); + let x = setupProxy('http://blahblah', { http_proxy: '123' }, { no_proxy: 'blah' }); expect(x.proxy).toEqual('123'); - x = setupProxy('http://blah.blah', {}, {http_proxy: '123', no_proxy: 'blah'}); + x = setupProxy('http://blah.blah', {}, { http_proxy: '123', no_proxy: 'blah' }); expect(x.proxy).toEqual(undefined); - x = setupProxy('http://blahblah', {}, {http_proxy: '123', no_proxy: '.blah'}); + x = setupProxy('http://blahblah', {}, { http_proxy: '123', no_proxy: '.blah' }); expect(x.proxy).toEqual('123'); - x = setupProxy('http://blah.blah', {http_proxy: '123', no_proxy: '.blah'}, {}); + x = setupProxy('http://blah.blah', { http_proxy: '123', no_proxy: '.blah' }, {}); expect(x.proxy).toEqual(undefined); - x = setupProxy('http://blah', {http_proxy: '123', no_proxy: '.blah'}, {}); + x = setupProxy('http://blah', { http_proxy: '123', no_proxy: '.blah' }, {}); expect(x.proxy).toEqual(undefined); - x = setupProxy('http://blahh', {http_proxy: '123', no_proxy: 'blah'}, {}); + x = setupProxy('http://blahh', { http_proxy: '123', no_proxy: 'blah' }, {}); expect(x.proxy).toEqual('123'); }); test('no_proxy - various, array', () => { - let x = setupProxy('http://blahblah', {http_proxy: '123'}, {no_proxy: 'foo,bar,blah'}); + let x = setupProxy('http://blahblah', { http_proxy: '123' }, { no_proxy: 'foo,bar,blah' }); expect(x.proxy).toEqual('123'); - x = setupProxy('http://blah.blah', {http_proxy: '123'}, {no_proxy: 'foo,bar,blah'}); + x = setupProxy('http://blah.blah', { http_proxy: '123' }, { no_proxy: 'foo,bar,blah' }); expect(x.proxy).toEqual(undefined); - x = setupProxy('http://blah.foo', {http_proxy: '123'}, {no_proxy: 'foo,bar,blah'}); + x = setupProxy('http://blah.foo', { http_proxy: '123' }, { no_proxy: 'foo,bar,blah' }); expect(x.proxy).toEqual(undefined); - x = setupProxy('http://foo.baz', {http_proxy: '123'}, {no_proxy: 'foo,bar,blah'}); + x = setupProxy('http://foo.baz', { http_proxy: '123' }, { no_proxy: 'foo,bar,blah' }); expect(x.proxy).toEqual('123'); - x = setupProxy('http://blahblah', {http_proxy: '123'}, {no_proxy: ['foo', 'bar', 'blah']}); + x = setupProxy('http://blahblah', { http_proxy: '123' }, { no_proxy: ['foo', 'bar', 'blah'] }); expect(x.proxy).toEqual('123'); - x = setupProxy('http://blah.blah', {http_proxy: '123'}, {no_proxy: ['foo', 'bar', 'blah']}); + x = setupProxy('http://blah.blah', { http_proxy: '123' }, { no_proxy: ['foo', 'bar', 'blah'] }); expect(x.proxy).toEqual(undefined); }); test('no_proxy - hostport', () => { - let x = setupProxy('http://localhost:80', {http_proxy: '123'}, {no_proxy: 'localhost'}); + let x = setupProxy('http://localhost:80', { http_proxy: '123' }, { no_proxy: 'localhost' }); expect(x.proxy).toEqual(undefined); - x = setupProxy('http://localhost:8080', {http_proxy: '123'}, {no_proxy: 'localhost'}); + x = setupProxy('http://localhost:8080', { http_proxy: '123' }, { no_proxy: 'localhost' }); expect(x.proxy).toEqual(undefined); }); test('no_proxy - secure', () => { - let x = setupProxy('https://something', {http_proxy: '123'}, {}); + let x = setupProxy('https://something', { http_proxy: '123' }, {}); expect(x.proxy).toEqual(undefined); - x = setupProxy('https://something', {https_proxy: '123'}, {}); + x = setupProxy('https://something', { https_proxy: '123' }, {}); expect(x.proxy).toEqual('123'); - x = setupProxy('https://something', {http_proxy: '456', https_proxy: '123'}, {}); + x = setupProxy('https://something', { http_proxy: '456', https_proxy: '123' }, {}); expect(x.proxy).toEqual('123'); }); }); diff --git a/test/unit/modules/uplinks/up-storage.spec.ts b/test/unit/modules/uplinks/up-storage.spec.ts index 8227e89c5..f13f00616 100644 --- a/test/unit/modules/uplinks/up-storage.spec.ts +++ b/test/unit/modules/uplinks/up-storage.spec.ts @@ -2,13 +2,13 @@ import _ from 'lodash'; import ProxyStorage from '../../../../src/lib/up-storage'; import AppConfig from '../../../../src/lib/config'; import configExample from '../../partials/config'; -import {setup} from '../../../../src/lib/logger'; +import { setup } from '../../../../src/lib/logger'; -import {Config, UpLinkConf} from '@verdaccio/types'; -import {IProxy} from '../../../../types'; -import {API_ERROR, HTTP_STATUS} from "../../../../src/lib/constants"; -import {mockServer} from '../../__helper/mock'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; +import { Config, UpLinkConf } from '@verdaccio/types'; +import { IProxy } from '../../../../types'; +import { API_ERROR, HTTP_STATUS } from '../../../../src/lib/constants'; +import { mockServer } from '../../__helper/mock'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; import { VerdaccioError } from '@verdaccio/commons-api'; setup([]); @@ -29,7 +29,7 @@ describe('UpStorge', () => { mockRegistry = await mockServer(mockServerPort).init(); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); @@ -55,7 +55,7 @@ describe('UpStorge', () => { test('should be get remote metadata with etag', (done) => { const proxy = generateProxy(); - proxy.getRemoteMetadata('jquery', {etag: '123456'}, (err, data, etag) => { + proxy.getRemoteMetadata('jquery', { etag: '123456' }, (err, data, etag) => { expect(err).toBeNull(); expect(_.isString(etag)).toBeTruthy(); expect(data.name).toBe('jquery'); @@ -66,7 +66,7 @@ describe('UpStorge', () => { test('should be get remote metadata package does not exist', (done) => { const proxy = generateProxy(); - proxy.getRemoteMetadata('@verdaccio/fake-package', {etag: '123456'}, (err) => { + 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); @@ -75,23 +75,21 @@ describe('UpStorge', () => { }); }); - describe('UpStorge::fetchTarball', () => { test('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) { + stream.on('error', function (err) { expect(err).toBeNull(); done(); }); - stream.on('content-length', function(contentLength) { + stream.on('content-length', function (contentLength) { expect(contentLength).toBeDefined(); done(); }); - }); test('should throw a 404 on fetch a tarball from uplink', (done) => { @@ -99,7 +97,7 @@ describe('UpStorge', () => { const tarball = `http://${DOMAIN_SERVERS}:${mockServerPort}/jquery/-/no-exist-1.5.1.tgz`; const stream = proxy.fetchTarball(tarball); - stream.on('error', function(err: VerdaccioError) { + stream.on('error', function (err: VerdaccioError) { expect(err).not.toBeNull(); expect(err.statusCode).toBe(HTTP_STATUS.NOT_FOUND); expect(err.message).toMatch(API_ERROR.NOT_FILE_UPLINK); @@ -107,11 +105,10 @@ describe('UpStorge', () => { done(); }); - stream.on('content-length', function(contentLength) { + stream.on('content-length', function (contentLength) { expect(contentLength).toBeDefined(); done(); }); - }); test('should be offline uplink', (done) => { @@ -122,14 +119,14 @@ describe('UpStorge', () => { // 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) { + 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) { + streamSecondTry.on('error', function (err) { expect(err).not.toBeNull(); /* code: 'ENOTFOUND', @@ -138,7 +135,7 @@ describe('UpStorge', () => { // expect(err.statusCode).toBe(404); expect(proxy.failed_requests).toBe(2); const streamThirdTry = proxy.fetchTarball(tarball); - streamThirdTry.on('error', function(err: VerdaccioError) { + streamThirdTry.on('error', function (err: VerdaccioError) { expect(err).not.toBeNull(); expect(err.statusCode).toBe(HTTP_STATUS.INTERNAL_ERROR); expect(proxy.failed_requests).toBe(2); @@ -152,16 +149,16 @@ describe('UpStorge', () => { }); describe('UpStorge::isUplinkValid', () => { - describe('valid use cases', () => { const validateUpLink = ( url: string, - tarBallUrl = `${url}/artifactory/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz`) => { + tarBallUrl = `${url}/artifactory/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz` + ) => { const uplinkConf = { url }; const proxy: IProxy = generateProxy(uplinkConf); return proxy.isUplinkValid(tarBallUrl); - } + }; test('should validate tarball path against uplink', () => { expect(validateUpLink('https://artifactory.mydomain.com')).toBe(true); @@ -186,8 +183,12 @@ describe('UpStorge', () => { // 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); + 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', () => { @@ -232,7 +233,8 @@ describe('UpStorge', () => { 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 tarBallUrl = + 'https://subdomain.domain:4000/api/npm/npm/pk1-juan/-/pk1-juan-1.0.7.tgz'; const uplinkConf = { url }; const proxy: IProxy = generateProxy(uplinkConf); @@ -249,7 +251,5 @@ describe('UpStorge', () => { expect(proxy.isUplinkValid(tarBallUrl)).toBe(false); }); }); - }); - }); diff --git a/test/unit/modules/utils/api.__test.template.ts b/test/unit/modules/utils/api.__test.template.ts index 7775e425e..c83ac63fc 100644 --- a/test/unit/modules/utils/api.__test.template.ts +++ b/test/unit/modules/utils/api.__test.template.ts @@ -12,12 +12,12 @@ import path from 'path'; import rimraf from 'rimraf'; import endPointAPI from '../../../../src/api/index'; -import {mockServer} from '../../__helper/mock'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; -import {parseConfigFile} from '../../../../src/lib/utils'; -import {parseConfigurationFile} from '../../__helper'; -import {addUser} from '../../__helper/api'; -import {setup} from '../../../../src/lib/logger'; +import { mockServer } from '../../__helper/mock'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; +import { parseConfigFile } from '../../../../src/lib/utils'; +import { parseConfigurationFile } from '../../__helper'; +import { addUser } from '../../__helper/api'; +import { setup } from '../../../../src/lib/logger'; // we must start logging without output setup([]); @@ -33,7 +33,7 @@ describe('endpoint example unit test', () => { let app; let mockRegistry; - beforeAll(function(done) { + beforeAll(function (done) { // 1. We create a route for a custom storage folder for this test const store = path.join(__dirname, '../../partials/store/test-template-storage'); // 2. The port must be unique (at this point this is not automated, need to be checked manually) @@ -68,7 +68,7 @@ describe('endpoint example unit test', () => { }); }); - afterAll(function(done) { + afterAll(function (done) { // 10. Do not forget to stop the API, or it will run forever. mockRegistry[0].stop(); done(); diff --git a/test/unit/modules/utils/config-utils.spec.ts b/test/unit/modules/utils/config-utils.spec.ts index 7b7869b3d..245952f64 100644 --- a/test/unit/modules/utils/config-utils.spec.ts +++ b/test/unit/modules/utils/config-utils.spec.ts @@ -1,17 +1,17 @@ import path from 'path'; import _ from 'lodash'; -import {spliceURL} from '../../../../src/utils/string'; -import {parseConfigFile} from '../../../../src/lib/utils'; +import { spliceURL } from '../../../../src/utils/string'; +import { parseConfigFile } from '../../../../src/lib/utils'; import { getMatchedPackagesSpec, hasProxyTo, - normalisePackageAccess, sanityCheckUplinksProps, + normalisePackageAccess, + sanityCheckUplinksProps, uplinkSanityCheck } from '../../../../src/lib/config-utils'; -import {PACKAGE_ACCESS, ROLES} from '../../../../src/lib/constants'; +import { PACKAGE_ACCESS, ROLES } from '../../../../src/lib/constants'; describe('Config Utilities', () => { - const parseConfigurationFile = (conf) => { const { name, ext } = path.parse(conf); const format = ext.startsWith('.') ? ext.substring(1) : 'yaml'; @@ -20,38 +20,40 @@ describe('Config Utilities', () => { }; describe('uplinkSanityCheck', () => { - test('should test basic conversion', ()=> { - const uplinks = uplinkSanityCheck(parseConfigFile(parseConfigurationFile('uplink-basic')).uplinks); + test('should test basic conversion', () => { + const uplinks = uplinkSanityCheck( + parseConfigFile(parseConfigurationFile('uplink-basic')).uplinks + ); expect(Object.keys(uplinks)).toContain('server1'); expect(Object.keys(uplinks)).toContain('server2'); }); - test('should throw error on blacklisted uplink name', ()=> { - const {uplinks} = parseConfigFile(parseConfigurationFile('uplink-wrong')); + test('should throw error on blacklisted uplink name', () => { + const { uplinks } = parseConfigFile(parseConfigurationFile('uplink-wrong')); expect(() => { - uplinkSanityCheck(uplinks) + uplinkSanityCheck(uplinks); }).toThrow('CONFIG: reserved uplink name: anonymous'); }); }); describe('sanityCheckUplinksProps', () => { - test('should fails if url prop is missing', ()=> { - const {uplinks} = parseConfigFile(parseConfigurationFile('uplink-wrong')); + test('should fails if url prop is missing', () => { + const { uplinks } = parseConfigFile(parseConfigurationFile('uplink-wrong')); expect(() => { - sanityCheckUplinksProps(uplinks) + sanityCheckUplinksProps(uplinks); }).toThrow('CONFIG: no url for uplink: none-url'); }); - test('should bypass an empty uplink list', ()=> { + test('should bypass an empty uplink list', () => { // @ts-ignore expect(sanityCheckUplinksProps([])).toHaveLength(0); }); }); describe('normalisePackageAccess', () => { - test('should test basic conversion', ()=> { - const {packages} = parseConfigFile(parseConfigurationFile('pkgs-basic')); + test('should test basic conversion', () => { + const { packages } = parseConfigFile(parseConfigurationFile('pkgs-basic')); const access = normalisePackageAccess(packages); expect(access).toBeDefined(); @@ -62,8 +64,8 @@ describe('Config Utilities', () => { expect(all).toBeDefined(); }); - test('should define an empty publish array even if is not defined in packages', ()=> { - const {packages} = parseConfigFile(parseConfigurationFile('pkgs-basic-no-publish')); + test('should define an empty publish array even if is not defined in packages', () => { + const { packages } = parseConfigFile(parseConfigurationFile('pkgs-basic-no-publish')); const access = normalisePackageAccess(packages); const scoped = access[`${PACKAGE_ACCESS.SCOPE}`]; @@ -75,8 +77,8 @@ describe('Config Utilities', () => { expect(all.publish).toHaveLength(0); }); - test('should define an empty access array even if is not defined in packages', ()=> { - const {packages} = parseConfigFile(parseConfigurationFile('pkgs-basic-no-access')); + test('should define an empty access array even if is not defined in packages', () => { + const { packages } = parseConfigFile(parseConfigurationFile('pkgs-basic-no-access')); const access = normalisePackageAccess(packages); const scoped = access[`${PACKAGE_ACCESS.SCOPE}`]; @@ -88,8 +90,8 @@ describe('Config Utilities', () => { expect(all.access).toHaveLength(0); }); - test('should define an empty proxy array even if is not defined in package', ()=> { - const {packages} = parseConfigFile(parseConfigurationFile('pkgs-basic-no-proxy')); + test('should define an empty proxy array even if is not defined in package', () => { + const { packages } = parseConfigFile(parseConfigurationFile('pkgs-basic-no-proxy')); const access = normalisePackageAccess(packages); const scoped = access[`${PACKAGE_ACCESS.SCOPE}`]; @@ -101,8 +103,8 @@ describe('Config Utilities', () => { expect(all.proxy).toHaveLength(0); }); - test('should test multi user group definition', ()=> { - const {packages} = parseConfigFile(parseConfigurationFile('pkgs-multi-group')); + test('should test multi user group definition', () => { + const { packages } = parseConfigFile(parseConfigurationFile('pkgs-multi-group')); const access = normalisePackageAccess(packages); expect(access).toBeDefined(); @@ -121,12 +123,10 @@ describe('Config Utilities', () => { expect(all.access).toContain('$all'); expect(all.publish).toHaveLength(1); expect(all.publish).toContain('admin'); - }); - - test('should normalize deprecated packages into the new ones (backward props compatible)', ()=> { - const {packages} = parseConfigFile(parseConfigurationFile('deprecated-pkgs-basic')); + test('should normalize deprecated packages into the new ones (backward props compatible)', () => { + const { packages } = parseConfigFile(parseConfigurationFile('deprecated-pkgs-basic')); const access = normalisePackageAccess(packages); expect(access).toBeDefined(); @@ -161,7 +161,7 @@ describe('Config Utilities', () => { expect(all.proxy_access).toBeUndefined(); }); - test('should check not default packages access', ()=> { + test('should check not default packages access', () => { const { packages } = parseConfigFile(parseConfigurationFile('pkgs-empty')); const access = normalisePackageAccess(packages); expect(access).toBeDefined(); @@ -177,13 +177,12 @@ describe('Config Utilities', () => { expect(_.isArray(all.access)).toBeTruthy(); expect(all.publish).toBeDefined(); expect(_.isArray(all.publish)).toBeTruthy(); - }); }); describe('getMatchedPackagesSpec', () => { test('should test basic config', () => { - const {packages} = parseConfigFile(parseConfigurationFile('pkgs-custom')); + const { packages } = parseConfigFile(parseConfigurationFile('pkgs-custom')); // @ts-ignore expect(getMatchedPackagesSpec('react', packages).proxy).toMatch('facebook'); // @ts-ignore @@ -195,7 +194,7 @@ describe('Config Utilities', () => { }); test('should test no ** wildcard on config', () => { - const {packages} = parseConfigFile(parseConfigurationFile('pkgs-nosuper-wildcard-custom')); + const { packages } = parseConfigFile(parseConfigurationFile('pkgs-nosuper-wildcard-custom')); // @ts-ignore expect(getMatchedPackagesSpec('react', packages).proxy).toMatch('facebook'); // @ts-ignore @@ -209,7 +208,9 @@ describe('Config Utilities', () => { describe('hasProxyTo', () => { test('should test basic config', () => { - const packages = normalisePackageAccess(parseConfigFile(parseConfigurationFile('pkgs-basic')).packages); + const packages = normalisePackageAccess( + parseConfigFile(parseConfigurationFile('pkgs-basic')).packages + ); // react expect(hasProxyTo('react', 'facebook', packages)).toBeFalsy(); expect(hasProxyTo('react', 'google', packages)).toBeFalsy(); @@ -224,7 +225,9 @@ describe('Config Utilities', () => { }); test('should test resolve based on custom package access', () => { - const packages = normalisePackageAccess(parseConfigFile(parseConfigurationFile('pkgs-custom')).packages); + const packages = normalisePackageAccess( + parseConfigFile(parseConfigurationFile('pkgs-custom')).packages + ); // react expect(hasProxyTo('react', 'facebook', packages)).toBeTruthy(); expect(hasProxyTo('react', 'google', packages)).toBeFalsy(); @@ -239,7 +242,9 @@ describe('Config Utilities', () => { }); test('should not resolve any proxy', () => { - const packages = normalisePackageAccess(parseConfigFile(parseConfigurationFile('pkgs-empty')).packages); + const packages = normalisePackageAccess( + parseConfigFile(parseConfigurationFile('pkgs-empty')).packages + ); // react expect(hasProxyTo('react', 'npmjs', packages)).toBeFalsy(); expect(hasProxyTo('react', 'npmjs', packages)).toBeFalsy(); @@ -278,13 +283,13 @@ describe('Config Utilities', () => { }); test('parse invalid.json', () => { - expect(function ( ) { + expect(function () { parseConfigFile(parseConfigurationFile('invalid.json')); }).toThrow(/Error/); }); test('parse not-exists.json', () => { - expect(function ( ) { + expect(function () { parseConfigFile(parseConfigurationFile('not-exists.json')); }).toThrow(/Error/); }); @@ -298,13 +303,13 @@ describe('Config Utilities', () => { }); test('parse invalid.js', () => { - expect(function ( ) { + expect(function () { parseConfigFile(parseConfigurationFile('invalid.js')); }).toThrow(/Error/); }); test('parse not-exists.js', () => { - expect(function ( ) { + expect(function () { parseConfigFile(parseConfigurationFile('not-exists.js')); }).toThrow(/Error/); }); diff --git a/test/unit/modules/utils/parseInterval.spec.ts b/test/unit/modules/utils/parseInterval.spec.ts index beaabd752..5ea96380f 100644 --- a/test/unit/modules/utils/parseInterval.spec.ts +++ b/test/unit/modules/utils/parseInterval.spec.ts @@ -5,7 +5,7 @@ describe('Parse interval', () => { function addTest(str, res) { test('parse ' + str, () => { if (res === null) { - assert.throws(function() { + assert.throws(function () { console.log(parseInterval(str)); }); } else { @@ -18,17 +18,16 @@ describe('Parse interval', () => { addTest('1000', 1000000); addTest('1.5s', 1500); addTest('25ms', 25); - addTest('2m', 2*1000*60); - addTest('3h', 3*1000*60*60); - addTest('0.5d', 0.5*1000*60*60*24); - addTest('0.5w', 0.5*1000*60*60*24*7); - addTest('1M', 1000*60*60*24*30); + addTest('2m', 2 * 1000 * 60); + addTest('3h', 3 * 1000 * 60 * 60); + addTest('0.5d', 0.5 * 1000 * 60 * 60 * 24); + addTest('0.5w', 0.5 * 1000 * 60 * 60 * 24 * 7); + addTest('1M', 1000 * 60 * 60 * 24 * 30); addTest('5s 20ms', 5020); - addTest('1y', 1000*60*60*24*365); + addTest('1y', 1000 * 60 * 60 * 24 * 365); addTest('1y 5', null); addTest('1m 1m', null); addTest('1m 1y', null); addTest('1y 1M 1w 1d 1h 1m 1s 1ms', 34822861001); addTest(' 5s 25ms ', 5025); }); - diff --git a/test/unit/modules/utils/tag.version.spec.ts b/test/unit/modules/utils/tag.version.spec.ts index 79deee1bc..bc29647c3 100644 --- a/test/unit/modules/utils/tag.version.spec.ts +++ b/test/unit/modules/utils/tag.version.spec.ts @@ -8,44 +8,43 @@ setup([]); describe('tagVersion', () => { test('add new one', () => { let pkg = { - 'versions': {}, - 'dist-tags': {}, + versions: {}, + 'dist-tags': {} }; // @ts-ignore assert(tagVersion(pkg, '1.1.1', 'foo', {})); assert.deepEqual(pkg, { - 'versions': {}, - 'dist-tags': {foo: '1.1.1'}, + versions: {}, + 'dist-tags': { foo: '1.1.1' } }); }); test('add (compat)', () => { const x = { - 'versions': {}, - 'dist-tags': {foo: '1.1.0'}, + versions: {}, + 'dist-tags': { foo: '1.1.0' } }; // @ts-ignore assert(tagVersion(x, '1.1.1', 'foo')); assert.deepEqual(x, { - 'versions': {}, - 'dist-tags': {foo: '1.1.1'}, + versions: {}, + 'dist-tags': { foo: '1.1.1' } }); }); test('add fresh tag', () => { let x = { - 'versions': {}, - 'dist-tags': {foo: '1.1.0'}, + versions: {}, + 'dist-tags': { foo: '1.1.0' } }; // @ts-ignore assert(tagVersion(x, '1.1.1', 'foo')); assert.deepEqual(x, { - 'versions': {}, - 'dist-tags': {foo: '1.1.1'}, + versions: {}, + 'dist-tags': { foo: '1.1.1' } }); }); }); - diff --git a/test/unit/modules/utils/utils.spec.ts b/test/unit/modules/utils/utils.spec.ts index 46a8c0f5f..b4360c654 100644 --- a/test/unit/modules/utils/utils.spec.ts +++ b/test/unit/modules/utils/utils.spec.ts @@ -1,4 +1,4 @@ -import {generateGravatarUrl, GENERIC_AVATAR } from '../../../../src/utils/user'; +import { generateGravatarUrl, GENERIC_AVATAR } from '../../../../src/utils/user'; import { spliceURL } from '../../../../src/utils/string'; import { validateName, @@ -14,20 +14,18 @@ import { getVersionFromTarball, sortByName, formatAuthor, - isHTTPProtocol, + isHTTPProtocol } from '../../../../src/lib/utils'; import { DIST_TAGS, DEFAULT_USER } from '../../../../src/lib/constants'; import { logger, setup } from '../../../../src/lib/logger'; import { readFile } from '../../../functional/lib/test.utils'; -const readmeFile = (fileName = 'markdown.md') => - readFile(`../../unit/partials/readme/${fileName}`); +const readmeFile = (fileName = 'markdown.md') => readFile(`../../unit/partials/readme/${fileName}`); setup([]); describe('Utilities', () => { - const buildURI = (host, version) => - `http://${host}/npm_test/-/npm_test-${version}.tgz`; + const buildURI = (host, version) => `http://${host}/npm_test/-/npm_test-${version}.tgz`; const fakeHost = 'fake.com'; const metadata: any = { name: 'npm_test', @@ -99,50 +97,50 @@ describe('Utilities', () => { }); test('should have header priority over request protocol', () => { - expect(getWebProtocol("https", 'http')).toBe('https'); + expect(getWebProtocol('https', 'http')).toBe('https'); }); test('should have handle empty protocol', () => { - expect(getWebProtocol("https", '')).toBe('https'); + expect(getWebProtocol('https', '')).toBe('https'); }); describe('getWebProtocol and HAProxy variant', () => { // https://github.com/verdaccio/verdaccio/issues/695 test('should handle http', () => { - expect(getWebProtocol("http,http", 'https')).toBe('http'); + expect(getWebProtocol('http,http', 'https')).toBe('http'); }); test('should handle https', () => { - expect(getWebProtocol("https,https", 'http')).toBe('https'); + expect(getWebProtocol('https,https', 'http')).toBe('https'); }); }); }); describe('convertDistRemoteToLocalTarballUrls', () => { test('should build a URI for dist tarball based on new domain', () => { - const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), - { - headers: { - host: fakeHost - }, - // @ts-ignore - get: () => 'http', - protocol: 'http' - }); + const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), { + headers: { + host: fakeHost + }, + // @ts-ignore + get: () => 'http', + protocol: 'http' + }); 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')); }); test('should return same URI whether host is missing', () => { - const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), - { - headers: {}, - // @ts-ignore - get: () => 'http', - protocol: 'http' - }); - expect(convertDist.versions['1.0.0'].dist.tarball).toEqual(convertDist.versions['1.0.0'].dist.tarball); + const convertDist = convertDistRemoteToLocalTarballUrls(cloneMetadata(), { + headers: {}, + // @ts-ignore + get: () => 'http', + protocol: 'http' + }); + expect(convertDist.versions['1.0.0'].dist.tarball).toEqual( + convertDist.versions['1.0.0'].dist.tarball + ); }); }); @@ -153,7 +151,7 @@ describe('Utilities', () => { latest: '20000' }; - normalizeDistTags(pkg) + normalizeDistTags(pkg); expect(Object.keys(pkg[DIST_TAGS])).toHaveLength(0); }); @@ -162,9 +160,9 @@ describe('Utilities', () => { const pkg = cloneMetadata(); pkg[DIST_TAGS] = {}; - normalizeDistTags(pkg) + normalizeDistTags(pkg); - expect(pkg[DIST_TAGS]).toEqual({latest: '1.0.1'}); + expect(pkg[DIST_TAGS]).toEqual({ latest: '1.0.1' }); }); test('should define last published version as latest with a custom dist-tag', () => { @@ -175,7 +173,7 @@ describe('Utilities', () => { normalizeDistTags(pkg); - expect(pkg[DIST_TAGS]).toEqual({beta: '1.0.1', latest: '1.0.1'}); + expect(pkg[DIST_TAGS]).toEqual({ beta: '1.0.1', latest: '1.0.1' }); }); test('should convert any array of dist-tags to a plain string', () => { @@ -186,7 +184,7 @@ describe('Utilities', () => { normalizeDistTags(pkg); - expect(pkg[DIST_TAGS]).toEqual({latest: '1.0.1'}); + expect(pkg[DIST_TAGS]).toEqual({ latest: '1.0.1' }); }); }); @@ -203,37 +201,38 @@ describe('Utilities', () => { expect(getVersion(cloneMetadata(), undefined)).toBeUndefined(); expect(getVersion(cloneMetadata(), null)).toBeUndefined(); expect(getVersion(cloneMetadata(), 2)).toBeUndefined(); - }) + }); }); describe('combineBaseUrl', () => { test('should create a URI', () => { - expect(combineBaseUrl("http", 'domain')).toEqual('http://domain'); + expect(combineBaseUrl('http', 'domain')).toEqual('http://domain'); }); test('should create a base url for registry', () => { - expect(combineBaseUrl("http", 'domain', '')).toEqual('http://domain'); - expect(combineBaseUrl("http", 'domain', '/')).toEqual('http://domain'); - expect(combineBaseUrl("http", 'domain', '/prefix/')).toEqual('http://domain/prefix'); - expect(combineBaseUrl("http", 'domain', '/prefix/deep')).toEqual('http://domain/prefix/deep'); - expect(combineBaseUrl("http", 'domain', 'only-prefix')).toEqual('only-prefix'); + expect(combineBaseUrl('http', 'domain', '')).toEqual('http://domain'); + expect(combineBaseUrl('http', 'domain', '/')).toEqual('http://domain'); + expect(combineBaseUrl('http', 'domain', '/prefix/')).toEqual('http://domain/prefix'); + expect(combineBaseUrl('http', 'domain', '/prefix/deep')).toEqual( + 'http://domain/prefix/deep' + ); + expect(combineBaseUrl('http', 'domain', 'only-prefix')).toEqual('only-prefix'); }); - }); describe('validatePackage', () => { test('should validate package names', () => { - expect(validatePackage("package-name")).toBeTruthy(); - expect(validatePackage("@scope/package-name")).toBeTruthy(); + expect(validatePackage('package-name')).toBeTruthy(); + expect(validatePackage('@scope/package-name')).toBeTruthy(); }); test('should fails on validate package names', () => { - expect(validatePackage("package-name/test/fake")).toBeFalsy(); - expect(validatePackage("@/package-name")).toBeFalsy(); - expect(validatePackage("$%$%#$%$#%#$%$#")).toBeFalsy(); - expect(validatePackage("node_modules")).toBeFalsy(); - expect(validatePackage("__proto__")).toBeFalsy(); - expect(validatePackage("favicon.ico")).toBeFalsy(); + expect(validatePackage('package-name/test/fake')).toBeFalsy(); + expect(validatePackage('@/package-name')).toBeFalsy(); + expect(validatePackage('$%$%#$%$#%#$%$#')).toBeFalsy(); + expect(validatePackage('node_modules')).toBeFalsy(); + expect(validatePackage('__proto__')).toBeFalsy(); + expect(validatePackage('favicon.ico')).toBeFalsy(); }); describe('validateName', () => { @@ -295,7 +294,7 @@ describe('Utilities', () => { }); test('should fails the assertions is not an object', () => { - expect(function ( ) { + expect(function () { // @ts-ignore validateMetadata(''); // @ts-ignore @@ -303,9 +302,9 @@ describe('Utilities', () => { }); test('should fails the assertions is name does not match', () => { - expect(function ( ) { + expect(function () { // @ts-ignore - validateMetadata({}, "no-name"); + validateMetadata({}, 'no-name'); // @ts-ignore }).toThrow(expect.hasAssertions()); }); @@ -313,17 +312,17 @@ describe('Utilities', () => { describe('getVersionFromTarball', () => { test('should get the right version', () => { - const simpleName = 'test-name-4.2.12.tgz' - const complexName = 'test-5.6.4-beta.2.tgz' - const otherComplexName = 'test-3.5.0-6.tgz' - expect(getVersionFromTarball(simpleName)).toEqual('4.2.12') - expect(getVersionFromTarball(complexName)).toEqual('5.6.4-beta.2') - expect(getVersionFromTarball(otherComplexName)).toEqual('3.5.0-6') - }) + const simpleName = 'test-name-4.2.12.tgz'; + const complexName = 'test-5.6.4-beta.2.tgz'; + const otherComplexName = 'test-3.5.0-6.tgz'; + expect(getVersionFromTarball(simpleName)).toEqual('4.2.12'); + expect(getVersionFromTarball(complexName)).toEqual('5.6.4-beta.2'); + expect(getVersionFromTarball(otherComplexName)).toEqual('3.5.0-6'); + }); - test('should don\'n fall at incorrect tarball name', () => { - expect(getVersionFromTarball('incorrectName')).toBeUndefined() - }) + test("should don'n fall at incorrect tarball name", () => { + expect(getVersionFromTarball('incorrectName')).toBeUndefined(); + }); }); }); @@ -379,12 +378,8 @@ describe('Utilities', () => { describe('parseReadme', () => { test('should parse makrdown text to html template', () => { const markdown = '# markdown'; - expect(parseReadme('testPackage', markdown)).toEqual( - '

markdown

' - ); - expect( - parseReadme('testPackage', String(readmeFile('markdown.md'))) - ).toMatchSnapshot(); + expect(parseReadme('testPackage', markdown)).toEqual('

markdown

'); + expect(parseReadme('testPackage', String(readmeFile('markdown.md')))).toMatchSnapshot(); }); test('should pass for conversion of non-ascii to markdown text', () => { @@ -392,12 +387,8 @@ describe('Utilities', () => { const randomText = '%%%%%**##=='; const randomTextMarkdown = 'simple text \n # markdown'; - expect(parseReadme('testPackage', randomText)).toEqual( - '

%%%%%**##==

' - ); - expect(parseReadme('testPackage', simpleText)).toEqual( - '

simple text

' - ); + expect(parseReadme('testPackage', randomText)).toEqual('

%%%%%**##==

'); + expect(parseReadme('testPackage', simpleText)).toEqual('

simple text

'); expect(parseReadme('testPackage', randomTextMarkdown)).toEqual( '

simple text

\n

markdown

' ); @@ -406,9 +397,7 @@ describe('Utilities', () => { test('should show error for no readme data', () => { const noData = ''; const spy = jest.spyOn(logger, 'error'); - expect(parseReadme('testPackage', noData)).toEqual( - '

ERROR: No README data found!

' - ); + expect(parseReadme('testPackage', noData)).toEqual('

ERROR: No README data found!

'); expect(spy).toHaveBeenCalledWith( { packageName: 'testPackage' }, '@{packageName}: No readme found' @@ -463,8 +452,7 @@ describe('Utilities', () => { const result = { latest: { author: { - avatar: - 'https://www.gravatar.com/avatar/794d7f6ef93d0689437de3c3e48fadc7', + avatar: 'https://www.gravatar.com/avatar/794d7f6ef93d0689437de3c3e48fadc7', email: 'user@verdccio.org', name: 'verdaccio' } @@ -486,7 +474,7 @@ describe('Utilities', () => { expect(addGravatarSupport(packageInfo)).toEqual(packageInfo); }); - describe("contributors", () => { + describe('contributors', () => { test('contributors field has contributors', () => { const packageInfo = { latest: { @@ -501,14 +489,12 @@ describe('Utilities', () => { latest: { contributors: [ { - avatar: - 'https://www.gravatar.com/avatar/794d7f6ef93d0689437de3c3e48fadc7', + avatar: 'https://www.gravatar.com/avatar/794d7f6ef93d0689437de3c3e48fadc7', email: 'user@verdccio.org', name: 'user' }, { - avatar: - 'https://www.gravatar.com/avatar/51105a49ce4a9c2bfabf0f6a2cba3762', + avatar: 'https://www.gravatar.com/avatar/51105a49ce4a9c2bfabf0f6a2cba3762', email: 'user1@verdccio.org', name: 'user1' } @@ -593,14 +579,12 @@ describe('Utilities', () => { latest: { maintainers: [ { - avatar: - 'https://www.gravatar.com/avatar/794d7f6ef93d0689437de3c3e48fadc7', + avatar: 'https://www.gravatar.com/avatar/794d7f6ef93d0689437de3c3e48fadc7', email: 'user@verdccio.org', name: 'user' }, { - avatar: - 'https://www.gravatar.com/avatar/51105a49ce4a9c2bfabf0f6a2cba3762', + avatar: 'https://www.gravatar.com/avatar/51105a49ce4a9c2bfabf0f6a2cba3762', email: 'user1@verdccio.org', name: 'user1' } diff --git a/test/unit/modules/web/api.web.spec.ts b/test/unit/modules/web/api.web.spec.ts index 0ab0fbf69..9aae329e2 100644 --- a/test/unit/modules/web/api.web.spec.ts +++ b/test/unit/modules/web/api.web.spec.ts @@ -7,10 +7,16 @@ import publishMetadata from '../../partials/publish-api'; import forbiddenPlace from '../../partials/forbidden-place'; import endPointAPI from '../../../../src/api'; -import { HEADERS, API_ERROR, HTTP_STATUS, HEADER_TYPE, DIST_TAGS} from '../../../../src/lib/constants'; -import {DOMAIN_SERVERS} from '../../../functional/config.functional'; -import {mockServer} from '../../__helper/mock'; -import {addUser} from '../../__helper/api'; +import { + HEADERS, + API_ERROR, + HTTP_STATUS, + HEADER_TYPE, + DIST_TAGS +} from '../../../../src/lib/constants'; +import { DOMAIN_SERVERS } from '../../../functional/config.functional'; +import { mockServer } from '../../__helper/mock'; +import { addUser } from '../../__helper/api'; require('../../../../src/lib/logger').setup([]); @@ -20,31 +26,34 @@ describe('endpoint web unit test', () => { let app; let mockRegistry; - beforeAll(function(done) { + beforeAll(function (done) { const store = path.join(__dirname, '../../partials/store/web-api-storage'); const mockServerPort = 55544; rimraf(store, async () => { - const configForTest = configDefault({ - auth: { - htpasswd: { - file: './web-api-storage/.htpasswd-web-api' - } + const configForTest = configDefault( + { + auth: { + htpasswd: { + file: './web-api-storage/.htpasswd-web-api' + } + }, + storage: store, + uplinks: { + npmjs: { + url: `http://${DOMAIN_SERVERS}:${mockServerPort}` + } + }, + self_path: store }, - storage: store, - uplinks: { - npmjs: { - url: `http://${DOMAIN_SERVERS}:${mockServerPort}` - } - }, - self_path: store - }, 'api.web.spec.yaml'); + 'api.web.spec.yaml' + ); app = await endPointAPI(configForTest); mockRegistry = await mockServer(mockServerPort).init(); done(); }); }); - afterAll(function(done) { + afterAll(function (done) { mockRegistry[0].stop(); done(); }); @@ -67,9 +76,9 @@ describe('endpoint web unit test', () => { describe('Packages', () => { test('should display all packages', (done) => { request(app) - .get('/-/verdaccio/packages' ) + .get('/-/verdaccio/packages') .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { expect(res.body).toHaveLength(1); done(); }); @@ -80,7 +89,7 @@ describe('endpoint web unit test', () => { .get('/-/verdaccio/package/readme/@scope/pk1-test') .expect(HTTP_STATUS.OK) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_CHARSET) - .end(function(err, res) { + .end(function (err, res) { expect(res.text).toMatch('

test

\n'); done(); }); @@ -92,7 +101,7 @@ describe('endpoint web unit test', () => { .get('/-/verdaccio/package/readme/@scope/404') .expect(HTTP_STATUS.OK) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_CHARSET) - .end(function(err, res) { + .end(function (err, res) { expect(res.body.error).toMatch(API_ERROR.NO_PACKAGE); done(); }); @@ -103,7 +112,7 @@ describe('endpoint web unit test', () => { .get('/-/verdaccio/sidebar/@scope/pk1-test') .expect(HTTP_STATUS.OK) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) - .end(function(err, res) { + .end(function (err, res) { const sideBarInfo = res.body; const latestVersion = publishMetadata.versions[publishMetadata[DIST_TAGS].latest]; @@ -120,7 +129,7 @@ describe('endpoint web unit test', () => { .get('/-/verdaccio/sidebar/@scope/pk1-test?v=1.0.6') .expect(HTTP_STATUS.OK) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) - .end(function(err, res) { + .end(function (err, res) { const sideBarInfo = res.body; const latestVersion = publishMetadata.versions[publishMetadata[DIST_TAGS].latest]; @@ -137,7 +146,7 @@ describe('endpoint web unit test', () => { .get('/-/verdaccio/sidebar/@scope/404') .expect(HTTP_STATUS.NOT_FOUND) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) - .end(function() { + .end(function () { done(); }); }); @@ -147,19 +156,18 @@ describe('endpoint web unit test', () => { .get('/-/verdaccio/sidebar/@scope/pk1-test?v=0.0.0-not-found') .expect(HTTP_STATUS.NOT_FOUND) .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET) - .end(function() { + .end(function () { done(); }); }); }); describe('Search', () => { - test('should search pk1-test', (done) => { request(app) .get('/-/verdaccio/search/scope') .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { expect(res.body).toHaveLength(1); done(); }); @@ -169,7 +177,7 @@ describe('endpoint web unit test', () => { request(app) .get('/-/verdaccio/search/@') .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { // in a normal world, the output would be 1 // https://github.com/verdaccio/verdaccio/issues/345 // should fix this @@ -182,7 +190,7 @@ describe('endpoint web unit test', () => { request(app) .get('/-/verdaccio/search/forbidden-place') .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { // this is expected since we are not logged // and forbidden-place is allow_access: 'nobody' expect(res.body).toHaveLength(0); @@ -205,7 +213,7 @@ describe('endpoint web unit test', () => { password: credentials.password }) .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { expect(res.body.error).toBeUndefined(); expect(res.body.token).toBeDefined(); expect(res.body.token).toBeTruthy(); @@ -217,13 +225,15 @@ describe('endpoint web unit test', () => { test('should fails on log unvalid user', (done) => { request(app) .post('/-/verdaccio/login') - .send(JSON.stringify({ - username: 'fake', - password: 'fake' - })) + .send( + JSON.stringify({ + username: 'fake', + password: 'fake' + }) + ) // FIXME: there should be 401 .expect(HTTP_STATUS.OK) - .end(function(err, res) { + .end(function (err, res) { expect(res.body.error).toMatch(/bad username\/password, access denied/); done(); }); diff --git a/types/index.ts b/types/index.ts index 01ed49fca..5b9742305 100644 --- a/types/index.ts +++ b/types/index.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/interface-name-prefix */ - import { IBasicAuth, IBasicStorage, @@ -197,7 +195,7 @@ export interface IStorageHandler extends IStorageManager, ITokenActions */ export interface Styles { [ruleOrSelector: string]: string | number | Styles; -}; +} export type AuthorAvatar = Author & { avatar?: string }; diff --git a/yarn.lock b/yarn.lock index 5a0e7e177..5ceed0d39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1684,7 +1684,17 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.13.9": +"@babel/runtime-corejs3@npm:^7.10.2": + version: 7.13.10 + resolution: "@babel/runtime-corejs3@npm:7.13.10" + dependencies: + core-js-pure: ^3.0.0 + regenerator-runtime: ^0.13.4 + checksum: cbf4de5c0e73197447c112b31e1e7bb48b7940c815fdc6e8aee28a9e33f57f5c3991ba0598dfbfb8bc4d22a7cfe3b2eced0f08c12f8e618aa2ccf73684ced051 + languageName: node + linkType: hard + +"@babel/runtime@npm:7.13.9, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2": version: 7.13.9 resolution: "@babel/runtime@npm:7.13.9" dependencies: @@ -2089,6 +2099,24 @@ __metadata: languageName: node linkType: hard +"@eslint/eslintrc@npm:^0.3.0": + version: 0.3.0 + resolution: "@eslint/eslintrc@npm:0.3.0" + dependencies: + ajv: ^6.12.4 + debug: ^4.1.1 + espree: ^7.3.0 + globals: ^12.1.0 + ignore: ^4.0.6 + import-fresh: ^3.2.1 + js-yaml: ^3.13.1 + lodash: ^4.17.20 + minimatch: ^3.0.4 + strip-json-comments: ^3.1.1 + checksum: 00e87c194672eb85dcea22ba749fb3cabdd9768e952e748b2c727940f06691c873369d75cf3bddb239301eca8c38de6e098b0de4839fa7c16a2062e536e8ff5a + languageName: node + linkType: hard + "@istanbuljs/load-nyc-config@npm:^1.0.0": version: 1.1.0 resolution: "@istanbuljs/load-nyc-config@npm:1.1.0" @@ -2378,6 +2406,33 @@ __metadata: languageName: node linkType: hard +"@nodelib/fs.scandir@npm:2.1.4": + version: 2.1.4 + resolution: "@nodelib/fs.scandir@npm:2.1.4" + dependencies: + "@nodelib/fs.stat": 2.0.4 + run-parallel: ^1.1.9 + checksum: 30b3102ee37e1c1a0cb939a8e93f9a58b1637e2b4b546bb9143b3fb5efacd2abde3237a5313d5329bf1bc4231c418a77c3cb7f5434ce410e61a91ff4051cf215 + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.4, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.4 + resolution: "@nodelib/fs.stat@npm:2.0.4" + checksum: 6454a79e945dd55102b5c2e158813804ed349f9c1cc806f8754fca4587688a5d8e4115fc3eedbdf3d8a6b343169a6b664ecd8a7a42289eed210c686a4d0897c4 + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3": + version: 1.2.6 + resolution: "@nodelib/fs.walk@npm:1.2.6" + dependencies: + "@nodelib/fs.scandir": 2.1.4 + fastq: ^1.6.0 + checksum: d0503ffd0bb4172d5ac5d23993b14665f5f6d42a460a719ad97743ce71e60588d134cc60df12ca76be0e5e3a93c9a3156904d9296b78a8cdf19425c3423c0b58 + languageName: node + linkType: hard + "@octokit/auth-token@npm:^2.4.0": version: 2.4.4 resolution: "@octokit/auth-token@npm:2.4.4" @@ -2753,6 +2808,13 @@ __metadata: languageName: node linkType: hard +"@types/json5@npm:^0.0.29": + version: 0.0.29 + resolution: "@types/json5@npm:0.0.29" + checksum: 66e9ac0143ec521522c7bb670301e9836ee886207eeed1aab6d4854a1b19b404ab3a54cd8d449f9b1f13acc357f540be96f8ac2d1e86e301eab52ae0f9a4066f + languageName: node + linkType: hard + "@types/lodash@npm:4.14.157": version: 4.14.157 resolution: "@types/lodash@npm:4.14.157" @@ -2900,25 +2962,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:2.12.0": - version: 2.12.0 - resolution: "@typescript-eslint/eslint-plugin@npm:2.12.0" - dependencies: - "@typescript-eslint/experimental-utils": 2.12.0 - eslint-utils: ^1.4.3 - functional-red-black-tree: ^1.0.1 - regexpp: ^3.0.0 - tsutils: ^3.17.1 - peerDependencies: - "@typescript-eslint/parser": ^2.0.0 - eslint: ^5.0.0 || ^6.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: e7933364a94f6629c89e1c83c521d210761c617b63e428bc4647f3a65af0e6fa880bf097bfea288d030f73528563bb51a8c7dd63272066e73073fd5fa56ccb06 - languageName: node - linkType: hard - "@typescript-eslint/eslint-plugin@npm:2.9.0": version: 2.9.0 resolution: "@typescript-eslint/eslint-plugin@npm:2.9.0" @@ -2938,6 +2981,28 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:4.13.0": + version: 4.13.0 + resolution: "@typescript-eslint/eslint-plugin@npm:4.13.0" + dependencies: + "@typescript-eslint/experimental-utils": 4.13.0 + "@typescript-eslint/scope-manager": 4.13.0 + debug: ^4.1.1 + functional-red-black-tree: ^1.0.1 + lodash: ^4.17.15 + regexpp: ^3.0.0 + semver: ^7.3.2 + tsutils: ^3.17.1 + peerDependencies: + "@typescript-eslint/parser": ^4.0.0 + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 98f6ab92683965a75dfc966c3aa68d8b620b6fa5ff43048b7e249848c09c2a8bf7aaf7c4fa32b8c1203d8bc083279269ca291b12b5775d444806f9e22a4f21a1 + languageName: node + linkType: hard + "@typescript-eslint/experimental-utils@npm:2.10.0": version: 2.10.0 resolution: "@typescript-eslint/experimental-utils@npm:2.10.0" @@ -2951,19 +3016,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/experimental-utils@npm:2.12.0, @typescript-eslint/experimental-utils@npm:^2.5.0": - version: 2.12.0 - resolution: "@typescript-eslint/experimental-utils@npm:2.12.0" - dependencies: - "@types/json-schema": ^7.0.3 - "@typescript-eslint/typescript-estree": 2.12.0 - eslint-scope: ^5.0.0 - peerDependencies: - eslint: "*" - checksum: 6538a9b9b6f9c90e2699ef3e93c39fdb65a09a1aa1094b6984e21d104fc3e71be5916bbd5b5cfff1c824bf72369cf94798f0b41bf36c6f94c114570b90b8e9fa - languageName: node - linkType: hard - "@typescript-eslint/experimental-utils@npm:2.9.0": version: 2.9.0 resolution: "@typescript-eslint/experimental-utils@npm:2.9.0" @@ -2977,6 +3029,51 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/experimental-utils@npm:4.13.0": + version: 4.13.0 + resolution: "@typescript-eslint/experimental-utils@npm:4.13.0" + dependencies: + "@types/json-schema": ^7.0.3 + "@typescript-eslint/scope-manager": 4.13.0 + "@typescript-eslint/types": 4.13.0 + "@typescript-eslint/typescript-estree": 4.13.0 + eslint-scope: ^5.0.0 + eslint-utils: ^2.0.0 + peerDependencies: + eslint: "*" + checksum: 63eee348ddc77bca7547be8a3b8759e4bcff30cf8a04e27a224bf8221d68ad8e4e1634fdd0aebdff7dc29d32a82dfa6ee70ec03d7d69d3c7128ae221f2711d1a + languageName: node + linkType: hard + +"@typescript-eslint/experimental-utils@npm:^2.5.0": + version: 2.12.0 + resolution: "@typescript-eslint/experimental-utils@npm:2.12.0" + dependencies: + "@types/json-schema": ^7.0.3 + "@typescript-eslint/typescript-estree": 2.12.0 + eslint-scope: ^5.0.0 + peerDependencies: + eslint: "*" + checksum: 6538a9b9b6f9c90e2699ef3e93c39fdb65a09a1aa1094b6984e21d104fc3e71be5916bbd5b5cfff1c824bf72369cf94798f0b41bf36c6f94c114570b90b8e9fa + languageName: node + linkType: hard + +"@typescript-eslint/experimental-utils@npm:^4.0.1": + version: 4.17.0 + resolution: "@typescript-eslint/experimental-utils@npm:4.17.0" + dependencies: + "@types/json-schema": ^7.0.3 + "@typescript-eslint/scope-manager": 4.17.0 + "@typescript-eslint/types": 4.17.0 + "@typescript-eslint/typescript-estree": 4.17.0 + eslint-scope: ^5.0.0 + eslint-utils: ^2.0.0 + peerDependencies: + eslint: "*" + checksum: 47ce799425c766cd8b6b4b81f1091c2485cf273925c328315af66b0e68241f3d6af1732bbe00f446474e6e269c4e84dab1d2ede6e5d7393099dd182b0458b096 + languageName: node + linkType: hard + "@typescript-eslint/parser@npm:2.10.0": version: 2.10.0 resolution: "@typescript-eslint/parser@npm:2.10.0" @@ -2991,6 +3088,57 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:4.13.0": + version: 4.13.0 + resolution: "@typescript-eslint/parser@npm:4.13.0" + dependencies: + "@typescript-eslint/scope-manager": 4.13.0 + "@typescript-eslint/types": 4.13.0 + "@typescript-eslint/typescript-estree": 4.13.0 + debug: ^4.1.1 + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 7eec410392d618eddfa421fd6d1449bba1312abc90bd81dcbea33d3083788616c50e97e98ac11fbce1600f827fc7d04e50296f56366fcdd37a54b08558812319 + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:4.13.0": + version: 4.13.0 + resolution: "@typescript-eslint/scope-manager@npm:4.13.0" + dependencies: + "@typescript-eslint/types": 4.13.0 + "@typescript-eslint/visitor-keys": 4.13.0 + checksum: 878302870ee46f5b311bcee7984514eb4f81caea618010983abd75f5395faf9b6ca2c76f82d43b221946672494fac593c697b5b8644d7a3ae70fc03b9c166d12 + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:4.17.0": + version: 4.17.0 + resolution: "@typescript-eslint/scope-manager@npm:4.17.0" + dependencies: + "@typescript-eslint/types": 4.17.0 + "@typescript-eslint/visitor-keys": 4.17.0 + checksum: 0b4eedc7c209b5006db027b58883356657352483baba61eecbbaa78c3255daadfdbde24dfc6bfae504e4208bf84b6b9e010fcf5187870ee9144e9075597d2912 + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:4.13.0": + version: 4.13.0 + resolution: "@typescript-eslint/types@npm:4.13.0" + checksum: ed2e27ad1f7d0db28d13d3a5fe900b7638981689fea1b5556de4fcd87729f73cfe2e3792005cf4e05ba4c405f2abe9bc55c076354d4ac3f9576ded65c1b4ddf5 + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:4.17.0": + version: 4.17.0 + resolution: "@typescript-eslint/types@npm:4.17.0" + checksum: a94e1b1d0284f04a0e73b1b7acfcf732a7eb489e06bff671fdbf1ec1c964a01987bff8701cb6e6b54c3450bf976444ae2fcbae6d76177cc04ddc4c452fd6d75f + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:2.10.0": version: 2.10.0 resolution: "@typescript-eslint/typescript-estree@npm:2.10.0" @@ -3045,6 +3193,63 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:4.13.0": + version: 4.13.0 + resolution: "@typescript-eslint/typescript-estree@npm:4.13.0" + dependencies: + "@typescript-eslint/types": 4.13.0 + "@typescript-eslint/visitor-keys": 4.13.0 + debug: ^4.1.1 + globby: ^11.0.1 + is-glob: ^4.0.1 + lodash: ^4.17.15 + semver: ^7.3.2 + tsutils: ^3.17.1 + peerDependenciesMeta: + typescript: + optional: true + checksum: 8b7485f192f247d659779f1bc95d927612e53b23801981acc462c2fd76219a61ac1094348bf7ac46034b58c1751793053128d11264268e378241eb6e686f5e8e + languageName: node + linkType: hard + +"@typescript-eslint/typescript-estree@npm:4.17.0": + version: 4.17.0 + resolution: "@typescript-eslint/typescript-estree@npm:4.17.0" + dependencies: + "@typescript-eslint/types": 4.17.0 + "@typescript-eslint/visitor-keys": 4.17.0 + debug: ^4.1.1 + globby: ^11.0.1 + is-glob: ^4.0.1 + semver: ^7.3.2 + tsutils: ^3.17.1 + peerDependenciesMeta: + typescript: + optional: true + checksum: 502af03c3ab2f58520afa77e772a7fd8bf428f504f776c04435b7038eecb89368463a3a5147a6a35f500de2c780449d9a33b30b17b149905344524eae9a6f2d3 + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:4.13.0": + version: 4.13.0 + resolution: "@typescript-eslint/visitor-keys@npm:4.13.0" + dependencies: + "@typescript-eslint/types": 4.13.0 + eslint-visitor-keys: ^2.0.0 + checksum: 35f20062885da380ef9d6e07f058ea9629a36b3d264dcf7e776e81da7c8f544373a287d6f49c88fd4fc546bb4afea27efdcd4e5be972c4202746b46cf1682a2d + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:4.17.0": + version: 4.17.0 + resolution: "@typescript-eslint/visitor-keys@npm:4.17.0" + dependencies: + "@typescript-eslint/types": 4.17.0 + eslint-visitor-keys: ^2.0.0 + checksum: 04156bce01aafde8127f1a87d356ee7c1ecb84eb223a11b3ede91722ffd704e2ba51161a9636185e2a95f0b80fddaeb2411edb233a820ab2b5dc16390254aa06 + languageName: node + linkType: hard + "@verdaccio/commons-api@npm:9.7.1, @verdaccio/commons-api@npm:^9.7.1": version: 9.7.1 resolution: "@verdaccio/commons-api@npm:9.7.1" @@ -3205,12 +3410,12 @@ __metadata: languageName: node linkType: hard -"acorn-jsx@npm:^5.1.0": - version: 5.1.0 - resolution: "acorn-jsx@npm:5.1.0" +"acorn-jsx@npm:^5.3.1": + version: 5.3.1 + resolution: "acorn-jsx@npm:5.3.1" peerDependencies: - acorn: ^6.0.0 || ^7.0.0 - checksum: efc57039e27db1b0104bcadead86b6bdd16a7806c8550e598f8b0b46edf815e0b1dd9fa3fd629576e894b460291fc463f0c78cb30613a45699d338c4f54913c6 + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 5925bc5d79a2821a8f7250b6de2b02bb86c0470dcb78cf68a603855291c5e50602b9eaf294aba2efbf3ee7063c80a9074b520b2330cc1aef80b849bfc7a041c0 languageName: node linkType: hard @@ -3239,6 +3444,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^7.4.0": + version: 7.4.1 + resolution: "acorn@npm:7.4.1" + bin: + acorn: bin/acorn + checksum: 2bde98c28c1be9a08e41e581179b776b43396c9486ce52b2b9848d73c53df38c516b7edba4bacdc84cabc9d7a3299f3b46ef240ae261c38dbf8ddd89f635bd32 + languageName: node + linkType: hard + "add-stream@npm:^1.0.0": version: 1.0.0 resolution: "add-stream@npm:1.0.0" @@ -3271,7 +3485,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.10.2": +"ajv@npm:^6.10.0": version: 6.10.2 resolution: "ajv@npm:6.10.2" dependencies: @@ -3307,6 +3521,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^7.0.2": + version: 7.2.1 + resolution: "ajv@npm:7.2.1" + dependencies: + fast-deep-equal: ^3.1.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + uri-js: ^4.2.2 + checksum: 34044f60ca45ef8ec850f5d09e4db340bb870639efc1694d54bec7ff4b06b12b077872949223f703d1507bbf3d553b59752f4c327ffcd25726ee27919d586037 + languageName: node + linkType: hard + "all-contributors-cli@npm:6.20.0": version: 6.20.0 resolution: "all-contributors-cli@npm:6.20.0" @@ -3327,6 +3553,13 @@ __metadata: languageName: node linkType: hard +"ansi-colors@npm:^4.1.1": + version: 4.1.1 + resolution: "ansi-colors@npm:4.1.1" + checksum: 50d8dfbce25602caea1b170ecf4c71c4c9c58d2d1e3186fb5712848c0610d05fe60b8bb6a9eaebd9b54f1db3baf6f603e04214cce597cc7799bc9f47fd9a797a + languageName: node + linkType: hard + "ansi-escapes@npm:^3.0.0": version: 3.2.0 resolution: "ansi-escapes@npm:3.2.0" @@ -3464,6 +3697,16 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:^4.2.2": + version: 4.2.2 + resolution: "aria-query@npm:4.2.2" + dependencies: + "@babel/runtime": ^7.10.2 + "@babel/runtime-corejs3": ^7.10.2 + checksum: dc7631b6f9aee453aee3587f1b4e998e2fca89909a7d2587d91694165d161850a8b64c433348efde78297e35473df6d79deb7abea8571f82485dad9b5401c390 + languageName: node + linkType: hard + "arr-diff@npm:^4.0.0": version: 4.0.0 resolution: "arr-diff@npm:4.0.0" @@ -3523,6 +3766,19 @@ __metadata: languageName: node linkType: hard +"array-includes@npm:^3.1.1, array-includes@npm:^3.1.2": + version: 3.1.3 + resolution: "array-includes@npm:3.1.3" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + es-abstract: ^1.18.0-next.2 + get-intrinsic: ^1.1.1 + is-string: ^1.0.5 + checksum: 0610b361162071ef8749827f3a6e171da03ac14a518d4d45a513b6c22a7c5017c55dcbea4d34d699ef006f1f148aa52e6d437e0101c93996da736d0055add173 + languageName: node + linkType: hard + "array-union@npm:^1.0.1": version: 1.0.2 resolution: "array-union@npm:1.0.2" @@ -3532,6 +3788,13 @@ __metadata: languageName: node linkType: hard +"array-union@npm:^2.1.0": + version: 2.1.0 + resolution: "array-union@npm:2.1.0" + checksum: 93af542eb854bf62a742192d0061c82788a963a9a6594628f367388f2b9f1bfd9215910febbbdd55074841555d8b59bda6a13ecba4a8e136f58b675499eda292 + languageName: node + linkType: hard + "array-uniq@npm:^1.0.1": version: 1.0.3 resolution: "array-uniq@npm:1.0.3" @@ -3546,6 +3809,29 @@ __metadata: languageName: node linkType: hard +"array.prototype.flat@npm:^1.2.3": + version: 1.2.4 + resolution: "array.prototype.flat@npm:1.2.4" + dependencies: + call-bind: ^1.0.0 + define-properties: ^1.1.3 + es-abstract: ^1.18.0-next.1 + checksum: b4936e68f8bb4ed8d6bf12eff4e19e93f263ee6ff66b0e394be275c0b168e2a4889740f105799ec1d19631e93020fba528534ca34dd0538e24d2a90043ebc6b0 + languageName: node + linkType: hard + +"array.prototype.flatmap@npm:^1.2.3": + version: 1.2.4 + resolution: "array.prototype.flatmap@npm:1.2.4" + dependencies: + call-bind: ^1.0.0 + define-properties: ^1.1.3 + es-abstract: ^1.18.0-next.1 + function-bind: ^1.1.1 + checksum: 2718f73b91e5f377fb230765c1ab1a67063d11f7d14b1edfa6283ba4129f710b2d2416003dc8c9fc25595d921a76430ed8a379f66e58d237e5f1f300b6465ece + languageName: node + linkType: hard + "arrify@npm:^1.0.1": version: 1.0.1 resolution: "arrify@npm:1.0.1" @@ -3583,6 +3869,13 @@ __metadata: languageName: node linkType: hard +"ast-types-flow@npm:^0.0.7": + version: 0.0.7 + resolution: "ast-types-flow@npm:0.0.7" + checksum: 4211a734ae7823e8ed55f68bd2cee5027a59ae3cbc8152f36485059859c5ef29560b0091fafdf40419ee42c433fe255c24ce54297e5cd299f8ded1a8eab7729c + languageName: node + linkType: hard + "astral-regex@npm:^1.0.0": version: 1.0.0 resolution: "astral-regex@npm:1.0.0" @@ -3590,6 +3883,13 @@ __metadata: languageName: node linkType: hard +"astral-regex@npm:^2.0.0": + version: 2.0.0 + resolution: "astral-regex@npm:2.0.0" + checksum: bf049ee7048b70af5473580020f98faf09159af31a7fa5e223099966dc90e9e87760bd34030e19a6dcac05b45614b428f559bd71f027344d123555e524cb95ac + languageName: node + linkType: hard + "async-each@npm:^1.0.1": version: 1.0.3 resolution: "async-each@npm:1.0.3" @@ -3648,6 +3948,20 @@ __metadata: languageName: node linkType: hard +"axe-core@npm:^4.0.2": + version: 4.1.3 + resolution: "axe-core@npm:4.1.3" + checksum: f711c530fb6b25a02dfde4a0410063a50b4f7bf7e4ee649376a51dcaceac61743e0de7b282a2798ccdbc512d2de22a62662211278da78ee039e56be54d75f090 + languageName: node + linkType: hard + +"axobject-query@npm:^2.2.0": + version: 2.2.0 + resolution: "axobject-query@npm:2.2.0" + checksum: c963a3ba9f30a402c32c6addf7798e6cf3471228d78b5c54bdd11f18d2b3da1bafe874bc6add142b93bf0ee0cb6a6fb3e48a992dea38ec2f5a52697498db3ac1 + languageName: node + linkType: hard + "babel-eslint@npm:10.0.3": version: 10.0.3 resolution: "babel-eslint@npm:10.0.3" @@ -4222,6 +4536,16 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind@npm:1.0.2" + dependencies: + function-bind: ^1.1.1 + get-intrinsic: ^1.0.2 + checksum: 18cc6107a1f028247f2b505dae73ad1c63b737addfcd43ff75159f072c5c827300c1fb66f26ee0ec70fc2fdd005ce68d65c05a2a34b74bab08c3b1921954ada9 + languageName: node + linkType: hard + "caller-callsite@npm:^2.0.0": version: 2.0.0 resolution: "caller-callsite@npm:2.0.0" @@ -4344,7 +4668,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:2.4.2, chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.1.0, chalk@npm:^2.3.1, chalk@npm:^2.4.1, chalk@npm:^2.4.2": +"chalk@npm:2.4.2, chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.3.1, chalk@npm:^2.4.1, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -5036,6 +5360,13 @@ __metadata: languageName: node linkType: hard +"core-js-pure@npm:^3.0.0": + version: 3.9.1 + resolution: "core-js-pure@npm:3.9.1" + checksum: 9cbb38523f6360c068991af52bb91a55cfdc3dd3cda0964b8e232caa795b95c08523d2fb1c80b76ffd2a8446e4822a6ba960f3bd762353ad0f8470f2fd3c652e + languageName: node + linkType: hard + "core-js@npm:^2.4.0, core-js@npm:^2.5.0, core-js@npm:^2.6.5": version: 2.6.9 resolution: "core-js@npm:2.6.9" @@ -5104,7 +5435,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^6.0.0, cross-spawn@npm:^6.0.5": +"cross-spawn@npm:^6.0.0": version: 6.0.5 resolution: "cross-spawn@npm:6.0.5" dependencies: @@ -5139,6 +5470,17 @@ __metadata: languageName: node linkType: hard +"cross-spawn@npm:^7.0.2": + version: 7.0.3 + resolution: "cross-spawn@npm:7.0.3" + dependencies: + path-key: ^3.1.0 + shebang-command: ^2.0.0 + which: ^2.0.1 + checksum: 51f10036f5f1de781be98f4738d58b50c6d44f4f471069b8ab075b21605893ba1548654880f7310a29a732d6fc7cd481da6026169b9f0831cab0148a62fb397a + languageName: node + linkType: hard + "cssom@npm:^0.4.1": version: 0.4.4 resolution: "cssom@npm:0.4.4" @@ -5178,6 +5520,13 @@ __metadata: languageName: node linkType: hard +"damerau-levenshtein@npm:^1.0.6": + version: 1.0.6 + resolution: "damerau-levenshtein@npm:1.0.6" + checksum: 46fbf25fc5cef33e8192ce6141c45bc8e265d7da63fdbca2f34b4bcfb580d28e8a30414b356ff0057bed018edccda1cb20d4ba16bd7ab34f14fcaa818bd4b88d + languageName: node + linkType: hard + "dargs@npm:^4.0.1": version: 4.1.0 resolution: "dargs@npm:4.1.0" @@ -5293,7 +5642,7 @@ __metadata: languageName: node linkType: hard -"deep-is@npm:~0.1.3": +"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": version: 0.1.3 resolution: "deep-is@npm:0.1.3" checksum: 3de58f86af4dec86c8be531a5abaf2e6d8ea98fa2f1d81a3a778d0d8df920ee282043a6ef05bfb4eb699c8551df9ac1b808d4dc71d54cc40ab1efa5ce8792943 @@ -5457,6 +5806,15 @@ __metadata: languageName: node linkType: hard +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: ^4.0.0 + checksum: 687fa3bd604f264042f325d9460e1298447fb32782f30cddc47cb302b742684d13e8ffce4c6f455e0ae92099d71e29f72387379c10b8fd3f6f1bf8992d7c0997 + languageName: node + linkType: hard + "doctrine@npm:1.5.0": version: 1.5.0 resolution: "doctrine@npm:1.5.0" @@ -5467,6 +5825,15 @@ __metadata: languageName: node linkType: hard +"doctrine@npm:^2.1.0": + version: 2.1.0 + resolution: "doctrine@npm:2.1.0" + dependencies: + esutils: ^2.0.2 + checksum: 4aa55e46757cc11bff8efa67cdb679dd89e87c954ea9d88fad5a9198cfe0a73748085503d29bebcb143487d720a759a6bbe81d6848c94da46a55c7a366b9834e + languageName: node + linkType: hard + "doctrine@npm:^3.0.0": version: 3.0.0 resolution: "doctrine@npm:3.0.0" @@ -5577,13 +5944,6 @@ __metadata: languageName: node linkType: hard -"emoji-regex@npm:^7.0.1": - version: 7.0.3 - resolution: "emoji-regex@npm:7.0.3" - checksum: e3a504cf5242061d9b3c78a88ce787d6beee37a5d21287c6ccdddf1fe665d5ef3eddfdda663d0baf683df8e7d354210eeb1458a7d9afdf0d7a28d48cbb9975e1 - languageName: node - linkType: hard - "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -5591,6 +5951,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^9.0.0": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: f3029ec432745ecb7cf5dcea1bc9ad3d70714ef20fcae1dc87a422d3be68913c42ed3adbb86765e7aa6c723c3bcd5833b5f4e22ed06d5e5cb74e0f628d4fc95b + languageName: node + linkType: hard + "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" @@ -5635,6 +6002,15 @@ __metadata: languageName: node linkType: hard +"enquirer@npm:^2.3.5": + version: 2.3.6 + resolution: "enquirer@npm:2.3.6" + dependencies: + ansi-colors: ^4.1.1 + checksum: e249bb97bf7d5a91d51081547ea5aa1d849604e5de74feff2c48f7174fc6c9dfcfeea42ef5536e9a3be58964a248c322d6897269ae7bba3e1b6d24f152d9d685 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.0 resolution: "env-paths@npm:2.2.0" @@ -5689,6 +6065,30 @@ __metadata: languageName: node linkType: hard +"es-abstract@npm:^1.18.0-next.1, es-abstract@npm:^1.18.0-next.2": + version: 1.18.0 + resolution: "es-abstract@npm:1.18.0" + dependencies: + call-bind: ^1.0.2 + es-to-primitive: ^1.2.1 + function-bind: ^1.1.1 + get-intrinsic: ^1.1.1 + has: ^1.0.3 + has-symbols: ^1.0.2 + is-callable: ^1.2.3 + is-negative-zero: ^2.0.1 + is-regex: ^1.1.2 + is-string: ^1.0.5 + object-inspect: ^1.9.0 + object-keys: ^1.1.1 + object.assign: ^4.1.2 + string.prototype.trimend: ^1.0.4 + string.prototype.trimstart: ^1.0.4 + unbox-primitive: ^1.0.0 + checksum: 019fa7c51e10532cd07ca3aa9b76e4c6ad6f421e15064205d144da08da54f8fc057edc262f6f95775e0b249ecbb753b497050dd75ab69a3c1c89cb9b734e42ca + languageName: node + linkType: hard + "es-abstract@npm:^1.5.1, es-abstract@npm:^1.7.0": version: 1.13.0 resolution: "es-abstract@npm:1.13.0" @@ -5714,6 +6114,17 @@ __metadata: languageName: node linkType: hard +"es-to-primitive@npm:^1.2.1": + version: 1.2.1 + resolution: "es-to-primitive@npm:1.2.1" + dependencies: + is-callable: ^1.1.4 + is-date-object: ^1.0.1 + is-symbol: ^1.0.2 + checksum: d20b7be268b84662469972ec7265a57d4d6a65b9bf2b73f040d75e14f9f6dbe266a1a88579162e11349f9cb70eaa17640efb515c90dab19745a904b680b14be3 + languageName: node + linkType: hard + "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" @@ -5776,6 +6187,17 @@ __metadata: languageName: node linkType: hard +"eslint-config-prettier@npm:7.2.0": + version: 7.2.0 + resolution: "eslint-config-prettier@npm:7.2.0" + peerDependencies: + eslint: ">=7.0.0" + bin: + eslint-config-prettier: bin/cli.js + checksum: 6812150ea49703cd64035527205b4905bc1edcd34646e71f71665e1acff9ab4648f872598389bdb209964093ad73993830a2c821ba12642764a5293513b92a58 + languageName: node + linkType: hard + "eslint-import-resolver-node@npm:^0.3.2": version: 0.3.2 resolution: "eslint-import-resolver-node@npm:0.3.2" @@ -5786,6 +6208,16 @@ __metadata: languageName: node linkType: hard +"eslint-import-resolver-node@npm:^0.3.4": + version: 0.3.4 + resolution: "eslint-import-resolver-node@npm:0.3.4" + dependencies: + debug: ^2.6.9 + resolve: ^1.13.1 + checksum: 825e34e662c988ece8229e6956a95f12d2fa19265b429e3e3db14e58bfe72e270c999cda0cfc690793ed6e6a3e49ffa8df0e0a8842d668a1f0f7de5ae1aa36f9 + languageName: node + linkType: hard + "eslint-module-utils@npm:^2.4.0": version: 2.4.1 resolution: "eslint-module-utils@npm:2.4.1" @@ -5796,6 +6228,16 @@ __metadata: languageName: node linkType: hard +"eslint-module-utils@npm:^2.6.0": + version: 2.6.0 + resolution: "eslint-module-utils@npm:2.6.0" + dependencies: + debug: ^2.6.9 + pkg-dir: ^2.0.0 + checksum: f584af176480a702eedcdb3f610797f8b8d1293c3835ed71fadb579ec28400b91ded5283729418f63d48dc27c6358bd66f2bd839614d565a1b78d3c3440ee8f7 + languageName: node + linkType: hard + "eslint-plugin-babel@npm:5.3.0": version: 5.3.0 resolution: "eslint-plugin-babel@npm:5.3.0" @@ -5807,6 +6249,17 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-babel@npm:5.3.1": + version: 5.3.1 + resolution: "eslint-plugin-babel@npm:5.3.1" + dependencies: + eslint-rule-composer: ^0.3.0 + peerDependencies: + eslint: ">=4.0.0" + checksum: 08bbbb2b944ae82d38c874c3b5e4eb8162fc2109d2a8de4e08704855df325d42c0a8a401fdb890c58ebc6bff1055759adeb145e6c99f90413d375af6cb5ba376 + languageName: node + linkType: hard + "eslint-plugin-import@npm:2.18.2": version: 2.18.2 resolution: "eslint-plugin-import@npm:2.18.2" @@ -5828,6 +6281,29 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-import@npm:2.22.1": + version: 2.22.1 + resolution: "eslint-plugin-import@npm:2.22.1" + dependencies: + array-includes: ^3.1.1 + array.prototype.flat: ^1.2.3 + contains-path: ^0.1.0 + debug: ^2.6.9 + doctrine: 1.5.0 + eslint-import-resolver-node: ^0.3.4 + eslint-module-utils: ^2.6.0 + has: ^1.0.3 + minimatch: ^3.0.4 + object.values: ^1.1.1 + read-pkg-up: ^2.0.0 + resolve: ^1.17.0 + tsconfig-paths: ^3.9.0 + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 + checksum: 35ae09ceae6f0fe239f6b72e134d58d74762ad1ed0f57aa989affb856354e46bc082bb6df9399b624989107efb9ab9af2c91c08f03c0c70c5cb46a37676591ec + languageName: node + linkType: hard + "eslint-plugin-jest@npm:23.1.1": version: 23.1.1 resolution: "eslint-plugin-jest@npm:23.1.1" @@ -5839,6 +6315,38 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-jest@npm:24.1.3": + version: 24.1.3 + resolution: "eslint-plugin-jest@npm:24.1.3" + dependencies: + "@typescript-eslint/experimental-utils": ^4.0.1 + peerDependencies: + eslint: ">=5" + checksum: d1b8f14d7553ee9cd1b85d4e3478439b9c2c789fff9b10f19f047c4aae83acb62b966a4fdd5182740a6d9339ac54d56e67be5e15f3326a53ea6b772753076cd7 + languageName: node + linkType: hard + +"eslint-plugin-jsx-a11y@npm:6.4.1": + version: 6.4.1 + resolution: "eslint-plugin-jsx-a11y@npm:6.4.1" + dependencies: + "@babel/runtime": ^7.11.2 + aria-query: ^4.2.2 + array-includes: ^3.1.1 + ast-types-flow: ^0.0.7 + axe-core: ^4.0.2 + axobject-query: ^2.2.0 + damerau-levenshtein: ^1.0.6 + emoji-regex: ^9.0.0 + has: ^1.0.3 + jsx-ast-utils: ^3.1.0 + language-tags: ^1.0.5 + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 + checksum: 680d13f5e3e23f7e9b5208c87fa81497bff31909796cbaf5f6245462e54f4bf6b5d03db97662eb67afb344d3f525ade0902472bc807b411b2c3806549faf7203 + languageName: node + linkType: hard + "eslint-plugin-prettier@npm:3.1.1": version: 3.1.1 resolution: "eslint-plugin-prettier@npm:3.1.1" @@ -5851,6 +6359,54 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-react-hooks@npm:4.2.0": + version: 4.2.0 + resolution: "eslint-plugin-react-hooks@npm:4.2.0" + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + checksum: 5378d16b5a56431a7a77b56d61464dbbfa343e8607da87b851a6caee44b96e08847147321f5f38de30d20668418691d859f69d9c5262dfb5308856382252096c + languageName: node + linkType: hard + +"eslint-plugin-react@npm:7.22.0": + version: 7.22.0 + resolution: "eslint-plugin-react@npm:7.22.0" + dependencies: + array-includes: ^3.1.1 + array.prototype.flatmap: ^1.2.3 + doctrine: ^2.1.0 + has: ^1.0.3 + jsx-ast-utils: ^2.4.1 || ^3.0.0 + object.entries: ^1.1.2 + object.fromentries: ^2.0.2 + object.values: ^1.1.1 + prop-types: ^15.7.2 + resolve: ^1.18.1 + string.prototype.matchall: ^4.0.2 + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 + checksum: 34927cb4880984e3a3e413ef57ebedbc4c4bf8e26f3cf561986e240c621d0873765fc5eef2be22171625deab2f77d0ec7013b422987ae5296fbdee0c682c6cc5 + languageName: node + linkType: hard + +"eslint-plugin-simple-import-sort@npm:7.0.0": + version: 7.0.0 + resolution: "eslint-plugin-simple-import-sort@npm:7.0.0" + peerDependencies: + eslint: ">=5.0.0" + checksum: 51fc6b675220681fd88e8fb7c0b9ff9b3b38e2c060999c72da7b0dee469cfe3fdbe1284374f2ade5015ee93d4d59eaf2d29c6185d4131b30aa057d9c9dec9483 + languageName: node + linkType: hard + +"eslint-plugin-verdaccio@npm:9.6.1": + version: 9.6.1 + resolution: "eslint-plugin-verdaccio@npm:9.6.1" + dependencies: + jsx-ast-utils: 2.2.3 + checksum: 5abfda7c76979442db8eb932786ec41eda0a584251cce6b933313f01738ae59b69346c87f24422c70d3dc32335a86a1f9572090d0df30734a1a3dbd5c321a910 + languageName: node + linkType: hard + "eslint-rule-composer@npm:^0.3.0": version: 0.3.0 resolution: "eslint-rule-composer@npm:0.3.0" @@ -5868,6 +6424,16 @@ __metadata: languageName: node linkType: hard +"eslint-scope@npm:^5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: ^4.3.0 + estraverse: ^4.1.1 + checksum: 79465cf5082f4216176f6d49c7d088de89ee890f912eb87b831f23ee9a5e17ed0f3f2ab6108fb8fefa0474ba5ebeaa9bdefbe49ba704bd879b73f2445e23ee10 + languageName: node + linkType: hard + "eslint-utils@npm:^1.4.3": version: 1.4.3 resolution: "eslint-utils@npm:1.4.3" @@ -5877,6 +6443,15 @@ __metadata: languageName: node linkType: hard +"eslint-utils@npm:^2.0.0, eslint-utils@npm:^2.1.0": + version: 2.1.0 + resolution: "eslint-utils@npm:2.1.0" + dependencies: + eslint-visitor-keys: ^1.1.0 + checksum: a43892372a4205374982ac9d4c8edc5fe180cba76535ab9184c48f18a3d931b7ffdd6862cb2f8ca4305c47eface0e614e39884a75fbf169fcc55a6131af2ec48 + languageName: node + linkType: hard + "eslint-visitor-keys@npm:^1.0.0, eslint-visitor-keys@npm:^1.1.0": version: 1.1.0 resolution: "eslint-visitor-keys@npm:1.1.0" @@ -5884,61 +6459,75 @@ __metadata: languageName: node linkType: hard -"eslint@npm:6.8.0": - version: 6.8.0 - resolution: "eslint@npm:6.8.0" +"eslint-visitor-keys@npm:^1.3.0": + version: 1.3.0 + resolution: "eslint-visitor-keys@npm:1.3.0" + checksum: 58ab7a0107621d8a0fe19142a5e1306fd527c0f36b65d5c79033639e80278d8060264804f42c56f68e5541c4cc83d9175f9143083774cec8222f6cd5a695306e + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^2.0.0": + version: 2.0.0 + resolution: "eslint-visitor-keys@npm:2.0.0" + checksum: 429dabdcab3c1cf5e65d44843afc513398d4ee32a37f93edc93bb5ba59a12b78fa67d87ff23c752c170b5e4f9085050f45b3c036cdfb23d40a724f2614048140 + languageName: node + linkType: hard + +"eslint@npm:7.19.0": + version: 7.19.0 + resolution: "eslint@npm:7.19.0" dependencies: "@babel/code-frame": ^7.0.0 + "@eslint/eslintrc": ^0.3.0 ajv: ^6.10.0 - chalk: ^2.1.0 - cross-spawn: ^6.0.5 + chalk: ^4.0.0 + cross-spawn: ^7.0.2 debug: ^4.0.1 doctrine: ^3.0.0 - eslint-scope: ^5.0.0 - eslint-utils: ^1.4.3 - eslint-visitor-keys: ^1.1.0 - espree: ^6.1.2 - esquery: ^1.0.1 + enquirer: ^2.3.5 + eslint-scope: ^5.1.1 + eslint-utils: ^2.1.0 + eslint-visitor-keys: ^2.0.0 + espree: ^7.3.1 + esquery: ^1.2.0 esutils: ^2.0.2 - file-entry-cache: ^5.0.1 + file-entry-cache: ^6.0.0 functional-red-black-tree: ^1.0.1 glob-parent: ^5.0.0 globals: ^12.1.0 ignore: ^4.0.6 import-fresh: ^3.0.0 imurmurhash: ^0.1.4 - inquirer: ^7.0.0 is-glob: ^4.0.0 js-yaml: ^3.13.1 json-stable-stringify-without-jsonify: ^1.0.1 - levn: ^0.3.0 - lodash: ^4.17.14 + levn: ^0.4.1 + lodash: ^4.17.20 minimatch: ^3.0.4 - mkdirp: ^0.5.1 natural-compare: ^1.4.0 - optionator: ^0.8.3 + optionator: ^0.9.1 progress: ^2.0.0 - regexpp: ^2.0.1 - semver: ^6.1.2 - strip-ansi: ^5.2.0 - strip-json-comments: ^3.0.1 - table: ^5.2.3 + regexpp: ^3.1.0 + semver: ^7.2.1 + strip-ansi: ^6.0.0 + strip-json-comments: ^3.1.0 + table: ^6.0.4 text-table: ^0.2.0 v8-compile-cache: ^2.0.3 bin: - eslint: ./bin/eslint.js - checksum: 796be0e038188d4cd8062541394d29f35606a7cee00cead5f6c8e3f9db932f0d19ee946df16fd593e0bcd614f896a416afa916bf82d9420576537ac349f2a06d + eslint: bin/eslint.js + checksum: 0461e8b2b53c9097995efe131f659e2df77deda1daf79d7673654e2cbdac90bd2a412758b0ee0db48d29bf58f4b4d99170a70e17df1345782f0c8fa511bb0734 languageName: node linkType: hard -"espree@npm:^6.1.2": - version: 6.1.2 - resolution: "espree@npm:6.1.2" +"espree@npm:^7.3.0, espree@npm:^7.3.1": + version: 7.3.1 + resolution: "espree@npm:7.3.1" dependencies: - acorn: ^7.1.0 - acorn-jsx: ^5.1.0 - eslint-visitor-keys: ^1.1.0 - checksum: aa1c3f928f896c3a1ddbeb5d61100dd140e99c11d25772df42f5c455cd39c92159edfcae98c740d18c498e45ea50a2486b9b1cdda46d2eaed9b857d4c1244504 + acorn: ^7.4.0 + acorn-jsx: ^5.3.1 + eslint-visitor-keys: ^1.3.0 + checksum: ff8e0f73939e1e76529b630cba65b6128e4d18ed7bf0b16af62022cadc73ddb950c7e5aa629cca74e8abebdf76f6dcd1cf873dbc819f10599827c6019e2f8e91 languageName: node linkType: hard @@ -5952,12 +6541,12 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.0.1": - version: 1.0.1 - resolution: "esquery@npm:1.0.1" +"esquery@npm:^1.2.0": + version: 1.4.0 + resolution: "esquery@npm:1.4.0" dependencies: - estraverse: ^4.0.0 - checksum: 6a002e2a2134da81f67849749d6c9c177a6120ccbe207d21971c6f3f4ae5a98a41513abd07bff55fb60ef1b8476a077145cf59641649625d1311b6e7407bce46 + estraverse: ^5.1.0 + checksum: 3293ecc1507a8cec8d2da8a4707275c2ccf5413e7a3c771fe41c16cee603cacd193bb7383a6e219d1f7d2449156ef575ffd66c839073d4a8058f72856a15f622 languageName: node linkType: hard @@ -5970,7 +6559,16 @@ __metadata: languageName: node linkType: hard -"estraverse@npm:^4.0.0, estraverse@npm:^4.1.0, estraverse@npm:^4.1.1": +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: ^5.2.0 + checksum: 2c96302dd5c4e6d07154d0ce6baee9e829ebf77e21c50c5ca4f24d6d0006fe4a4582364624a01f5667a3633b3e39bbce1a8191924f8419fb71584bb45bf7bb81 + languageName: node + linkType: hard + +"estraverse@npm:^4.1.0, estraverse@npm:^4.1.1": version: 4.2.0 resolution: "estraverse@npm:4.2.0" checksum: 1311f8a66780e0778b25531c875798105a3c4cf034ed28caa593e824da73af63cf91de47eeb9edd4780a2f956e033e662cc30a2df5dc49eeb300113fa8e9a88e @@ -5984,6 +6582,13 @@ __metadata: languageName: node linkType: hard +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": + version: 5.2.0 + resolution: "estraverse@npm:5.2.0" + checksum: 7dc1b027aebf937bab10c3254d9d73ed21672d7382518c9ddb9dc45560cb2f4e6548cc8ff1a07b7f431e94bd0fb0bf5da75b602e2473f966fea141c4c31b31d6 + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -6217,6 +6822,20 @@ __metadata: languageName: node linkType: hard +"fast-glob@npm:^3.1.1": + version: 3.2.5 + resolution: "fast-glob@npm:3.2.5" + dependencies: + "@nodelib/fs.stat": ^2.0.2 + "@nodelib/fs.walk": ^1.2.3 + glob-parent: ^5.1.0 + merge2: ^1.3.0 + micromatch: ^4.0.2 + picomatch: ^2.2.1 + checksum: 1a33c4a68d14cb2314c07a451689bc311bde87b09c525dd2064321165127a38a553457d121e2d3ecdd022374e3d53afb82cbb57f5694414d3406ce14ed6c0a1f + languageName: node + linkType: hard + "fast-json-stable-stringify@npm:^2.0.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" @@ -6224,7 +6843,7 @@ __metadata: languageName: node linkType: hard -"fast-levenshtein@npm:~2.0.6": +"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6": version: 2.0.6 resolution: "fast-levenshtein@npm:2.0.6" checksum: a2d03af3088b0397633e007fb3010ecfa4f91cae2116d2385653c59396a1b31467641afa672a79e6f82218518670dc144128378124e711e35dbf90bc82846f22 @@ -6238,6 +6857,15 @@ __metadata: languageName: node linkType: hard +"fastq@npm:^1.6.0": + version: 1.11.0 + resolution: "fastq@npm:1.11.0" + dependencies: + reusify: ^1.0.4 + checksum: 22822313d66aa7ef7fd392bf2da1cdf074dce902460bf73c0f0da6d58eb394ea8d74b8cce6c9466f5d659a51caeb732f4305cf8514ca8325490a4e3d873f5aa0 + languageName: node + linkType: hard + "fb-watchman@npm:^2.0.0": version: 2.0.0 resolution: "fb-watchman@npm:2.0.0" @@ -6284,12 +6912,12 @@ __metadata: languageName: node linkType: hard -"file-entry-cache@npm:^5.0.1": - version: 5.0.1 - resolution: "file-entry-cache@npm:5.0.1" +"file-entry-cache@npm:^6.0.0": + version: 6.0.1 + resolution: "file-entry-cache@npm:6.0.1" dependencies: - flat-cache: ^2.0.1 - checksum: 7140588becf15f05ee956cfb359b5f23e0c73acbbd38ad14c7a76a0097342e6bfc0a8151cd2e481ea3cbb735190ba9a0df4b69055ebb5b0389c62339b1a2f86b + flat-cache: ^3.0.4 + checksum: af83a412143100405a995bb7d9a31982ebcfabe6c545dac2e787fc5580b2da74e253ef62968057fa5bbfaf0811a8b85623aeea776e16c77e3ce4c2488b0e4821 languageName: node linkType: hard @@ -6406,21 +7034,20 @@ __metadata: languageName: node linkType: hard -"flat-cache@npm:^2.0.1": - version: 2.0.1 - resolution: "flat-cache@npm:2.0.1" +"flat-cache@npm:^3.0.4": + version: 3.0.4 + resolution: "flat-cache@npm:3.0.4" dependencies: - flatted: ^2.0.0 - rimraf: 2.6.3 - write: 1.0.3 - checksum: a36ba407553064be4a571cdee4021a50290f6179a0827df1d076a2e33cd84e543d0274cb15dbeb551c2ae6d53e611e3c02564a93f0d527563d0f560be7a14b0d + flatted: ^3.1.0 + rimraf: ^3.0.2 + checksum: 72d86ccdf840e70227168a20bb908db8bc382360f0b241efd4c2e5cf2d17a7d566c0849dc4c5d2e8e6d7838e052539dcc319f0cf295c0bb9f47b71844c1de78d languageName: node linkType: hard -"flatted@npm:^2.0.0": - version: 2.0.1 - resolution: "flatted@npm:2.0.1" - checksum: dd5140cc40a5c5457f024c6b7193e8581e15c0401c874cf8705b350c2f152f24c5b1794dfebf664bbce5542a4d861b5b96d0d55bf40b7cf708b22885f4bd8b8c +"flatted@npm:^3.1.0": + version: 3.1.1 + resolution: "flatted@npm:3.1.1" + checksum: 1065cd78294ea651b8c1b96c298a3e70893a23da655e2288e40c06d5d9b1ebce4bd977e604678e01065a92580f3de5078d60d9ee4cdcede9a9989859d7eb5057 languageName: node linkType: hard @@ -6657,6 +7284,17 @@ fsevents@~2.1.2: languageName: node linkType: hard +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.0, get-intrinsic@npm:^1.1.1": + version: 1.1.1 + resolution: "get-intrinsic@npm:1.1.1" + dependencies: + function-bind: ^1.1.1 + has: ^1.0.3 + has-symbols: ^1.0.1 + checksum: acf1506f25a32a194cfc5c19d33835756080d970eb6e29a8a3852380106df981acef7bb9ac2002689437235221f24bcbdc1e3532b9bcacd7ff3621091fafe607 + languageName: node + linkType: hard + "get-own-enumerable-property-symbols@npm:^3.0.0": version: 3.0.0 resolution: "get-own-enumerable-property-symbols@npm:3.0.0" @@ -6833,7 +7471,7 @@ fsevents@~2.1.2: languageName: node linkType: hard -"glob-parent@npm:^5.0.0, glob-parent@npm:~5.1.0": +"glob-parent@npm:^5.0.0, glob-parent@npm:^5.1.0, glob-parent@npm:~5.1.0": version: 5.1.0 resolution: "glob-parent@npm:5.1.0" dependencies: @@ -6894,6 +7532,20 @@ fsevents@~2.1.2: languageName: node linkType: hard +"globby@npm:^11.0.1": + version: 11.0.2 + resolution: "globby@npm:11.0.2" + dependencies: + array-union: ^2.1.0 + dir-glob: ^3.0.1 + fast-glob: ^3.1.1 + ignore: ^5.1.4 + merge2: ^1.3.0 + slash: ^3.0.0 + checksum: d23f2a6b8897b97fb27422cde243e0fd406ebbaa821929293b27c977d169884f8112494cda4f456a51d0ec1e133e3ac703ec24bfed484e327305ea34a665eb06 + languageName: node + linkType: hard + "globby@npm:^6.1.0": version: 6.1.0 resolution: "globby@npm:6.1.0" @@ -7004,6 +7656,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"has-bigints@npm:^1.0.0": + version: 1.0.1 + resolution: "has-bigints@npm:1.0.1" + checksum: 1074b644f5f2c319fc31af00fe2f81b6e21e204bb46da70ff7b970fe65c56f504e697fe6b41823ba679bd4111840482a83327d3432b8d670a684da4087ed074b + languageName: node + linkType: hard + "has-flag@npm:^3.0.0": version: 3.0.0 resolution: "has-flag@npm:3.0.0" @@ -7025,6 +7684,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"has-symbols@npm:^1.0.1, has-symbols@npm:^1.0.2": + version: 1.0.2 + resolution: "has-symbols@npm:1.0.2" + checksum: 1b73928752fa9ca993fa48f7b3832c95ea408c0ec635b2d6cbaf011b94a7e6a704a9254ae6d8ecc913d4dd92f2ff760dc43aad7c7e790ddb3f627005614d8e28 + languageName: node + linkType: hard + "has-unicode@npm:^2.0.0": version: 2.0.1 resolution: "has-unicode@npm:2.0.1" @@ -7258,6 +7924,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"ignore@npm:^5.1.4": + version: 5.1.8 + resolution: "ignore@npm:5.1.8" + checksum: b08e3d5b5d94eca13475f29a5d47d221060e9cdd7e38d7647088e29d90130669a970fecbc4cdb41b8fa295c6673740c729d3dc05dadc381f593efb42282cbf9f + languageName: node + linkType: hard + "immediate@npm:~3.2.3": version: 3.2.3 resolution: "immediate@npm:3.2.3" @@ -7295,6 +7968,16 @@ fsevents@~2.1.2: languageName: node linkType: hard +"import-fresh@npm:^3.2.1": + version: 3.3.0 + resolution: "import-fresh@npm:3.3.0" + dependencies: + parent-module: ^1.0.0 + resolve-from: ^4.0.0 + checksum: 3ff624f00140850a2878eb7630d635daaad556cfa5a0e23191e9b65ab4fec8cc23f929f03bc9b3c4251b497a434f459bf3e7a8aa547a400ad140f431a1b0e4d6 + languageName: node + linkType: hard + "import-local@npm:^3.0.2": version: 3.0.2 resolution: "import-local@npm:3.0.2" @@ -7380,27 +8063,6 @@ fsevents@~2.1.2: languageName: node linkType: hard -"inquirer@npm:^7.0.0": - version: 7.0.1 - resolution: "inquirer@npm:7.0.1" - dependencies: - ansi-escapes: ^4.2.1 - chalk: ^2.4.2 - cli-cursor: ^3.1.0 - cli-width: ^2.0.0 - external-editor: ^3.0.3 - figures: ^3.0.0 - lodash: ^4.17.15 - mute-stream: 0.0.8 - run-async: ^2.2.0 - rxjs: ^6.5.3 - string-width: ^4.1.0 - strip-ansi: ^5.1.0 - through: ^2.3.6 - checksum: 7a9f9568cd7a63f8ecab341ea9b15a0e19cd8d3963b012ad56742f60e9ca99e0a24841a7aded2e227e0cfd2e6110c6c8c068dcc73cba1539f6c79709d763e6ee - languageName: node - linkType: hard - "inquirer@npm:^7.0.4": version: 7.1.0 resolution: "inquirer@npm:7.1.0" @@ -7422,6 +8084,17 @@ fsevents@~2.1.2: languageName: node linkType: hard +"internal-slot@npm:^1.0.3": + version: 1.0.3 + resolution: "internal-slot@npm:1.0.3" + dependencies: + get-intrinsic: ^1.1.0 + has: ^1.0.3 + side-channel: ^1.0.4 + checksum: 2465f832aa80c3740f2cfc5c75e74c727b4a45b8d80e295bb66dbb59435de536b9951b7f4d1a8075d5bb90054bd30ff22a37356a247fba3608987c7765569345 + languageName: node + linkType: hard + "interpret@npm:^1.0.0": version: 1.4.0 resolution: "interpret@npm:1.4.0" @@ -7468,6 +8141,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"is-bigint@npm:^1.0.1": + version: 1.0.1 + resolution: "is-bigint@npm:1.0.1" + checksum: dd132ab80f389d6968315d491706c5dbb3f6c4bf35b64085d74895e7f3516123ab1bcf6a9a83a63cfede688f44550a08713ed37f3ae9153afe8d0cf569a8b956 + languageName: node + linkType: hard + "is-binary-path@npm:^1.0.0": version: 1.0.1 resolution: "is-binary-path@npm:1.0.1" @@ -7486,6 +8166,15 @@ fsevents@~2.1.2: languageName: node linkType: hard +"is-boolean-object@npm:^1.1.0": + version: 1.1.0 + resolution: "is-boolean-object@npm:1.1.0" + dependencies: + call-bind: ^1.0.0 + checksum: 1d6047a022aa49cdf8580ac8b3d6d25da0d33a65ae00142bec2ba95c6c889de84693a0ef5acc9eabb59ba9e66fb473f47fa589ec22dd8e7ef8d88b6774e3adc6 + languageName: node + linkType: hard + "is-buffer@npm:^1.1.5": version: 1.1.6 resolution: "is-buffer@npm:1.1.6" @@ -7500,6 +8189,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"is-callable@npm:^1.2.3": + version: 1.2.3 + resolution: "is-callable@npm:1.2.3" + checksum: 8180a1c4e227e204e199ff355c4f24a80f74536898e16716583aa6a09167f2cceecc188cea750a2f3ae3b163577691595ae8d22bf7bb94b4bbb9fbdfea1bc5c3 + languageName: node + linkType: hard + "is-ci@npm:^2.0.0": version: 2.0.0 resolution: "is-ci@npm:2.0.0" @@ -7663,6 +8359,20 @@ fsevents@~2.1.2: languageName: node linkType: hard +"is-negative-zero@npm:^2.0.1": + version: 2.0.1 + resolution: "is-negative-zero@npm:2.0.1" + checksum: e2160af9a6fad7027bbd513e1efe9a99c780bb6af688e61e6b71084b5893f976241ca081e1ed8c18222d391ea3c1c0771cd23ab322be107150b66faf03d6ecbd + languageName: node + linkType: hard + +"is-number-object@npm:^1.0.4": + version: 1.0.4 + resolution: "is-number-object@npm:1.0.4" + checksum: 5bae52129f0e097485da25cbe89307dd46cf5ce7640edb6fcf40350d59c9f909039713d35fbeb0f1de1df817da6ec6e88aceca41b01e5ac989f6fdfc15c438a7 + languageName: node + linkType: hard + "is-number@npm:^3.0.0": version: 3.0.0 resolution: "is-number@npm:3.0.0" @@ -7766,6 +8476,16 @@ fsevents@~2.1.2: languageName: node linkType: hard +"is-regex@npm:^1.1.2": + version: 1.1.2 + resolution: "is-regex@npm:1.1.2" + dependencies: + call-bind: ^1.0.2 + has-symbols: ^1.0.1 + checksum: 5e2f80f495f5297d1295730820a4be31f3848ca92357cfef1b2a61c09fe0fcd3f68c34f3042a5b81885e249cd50eac8efac472ad6da7ecb497bb2d7bad402a9a + languageName: node + linkType: hard + "is-regexp@npm:^1.0.0": version: 1.0.0 resolution: "is-regexp@npm:1.0.0" @@ -7787,6 +8507,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"is-string@npm:^1.0.5": + version: 1.0.5 + resolution: "is-string@npm:1.0.5" + checksum: c64c791eb75935db9055291bc598edc22f03d3879b8a050b2955ba8087642d006338a1dedf7ac414c95f985c77c2d6fce655498d33c0df248fa92228a9945720 + languageName: node + linkType: hard + "is-symbol@npm:^1.0.2": version: 1.0.2 resolution: "is-symbol@npm:1.0.2" @@ -7796,6 +8523,15 @@ fsevents@~2.1.2: languageName: node linkType: hard +"is-symbol@npm:^1.0.3": + version: 1.0.3 + resolution: "is-symbol@npm:1.0.3" + dependencies: + has-symbols: ^1.0.1 + checksum: 753aa0cf95069387521b110c6646df4e0b5cce76cf604521c26b4f5d30a997a95036ed5930c0cca9e850ac6fccb04de551cc95aab71df471ee88e04ed1a96f21 + languageName: node + linkType: hard + "is-text-path@npm:^1.0.1": version: 1.0.1 resolution: "is-text-path@npm:1.0.1" @@ -8472,7 +9208,7 @@ fsevents@~2.1.2: languageName: node linkType: hard -"js-tokens@npm:^4.0.0": +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 1fc4e4667ac2d972aba65148b9cbf9c17566b2394d3504238d8492bbd3e68f496c657eab06b26b40b17db5cac0a34d153a12130e2d2d2bb6dc2cdc8a4764eb1b @@ -8592,6 +9328,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 7a230bcd927f5bf41b33a822121730a225ac287e14d7e8abc94f4cbc36743f6e09455549abaada7029844f7e88a9fd693a023ec76296df17488746acb1e5a388 + languageName: node + linkType: hard + "json-schema@npm:0.2.3": version: 0.2.3 resolution: "json-schema@npm:0.2.3" @@ -8685,6 +9428,26 @@ fsevents@~2.1.2: languageName: node linkType: hard +"jsx-ast-utils@npm:2.2.3": + version: 2.2.3 + resolution: "jsx-ast-utils@npm:2.2.3" + dependencies: + array-includes: ^3.0.3 + object.assign: ^4.1.0 + checksum: a5eaa22bb221067f8ead1dd82aa9ae53c737ff5dc788934d9f509c058da62445ee9b86d06f7cf8d875bce7ebbb581ffe18400c6c48f6a64ac896929bce66e0e7 + languageName: node + linkType: hard + +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.1.0": + version: 3.2.0 + resolution: "jsx-ast-utils@npm:3.2.0" + dependencies: + array-includes: ^3.1.2 + object.assign: ^4.1.2 + checksum: 2a8033e63234d04e6ed77ac91222e2dff527f64cf70c10d2f26fda6f35dc9b78d5e3a43fc3d28df7fe0dab45294b94c9c90e58ab242ecf14e58cd39691ee0ed4 + languageName: node + linkType: hard + "jwa@npm:^1.4.1": version: 1.4.1 resolution: "jwa@npm:1.4.1" @@ -8768,6 +9531,22 @@ fsevents@~2.1.2: languageName: node linkType: hard +"language-subtag-registry@npm:~0.3.2": + version: 0.3.21 + resolution: "language-subtag-registry@npm:0.3.21" + checksum: 91bcb4717a5a64ddb86b720807081c7f4aff05b22cb813652ad6f2ea745008170bec244b74212c1f6d84ab21a63a854f3fb569386544f1fb61297e07492c1a1f + languageName: node + linkType: hard + +"language-tags@npm:^1.0.5": + version: 1.0.5 + resolution: "language-tags@npm:1.0.5" + dependencies: + language-subtag-registry: ~0.3.2 + checksum: a3d30a911884eadc0f738dedf1c1cb345d8f8dce5c0a8790a75102f02a0b44cbcba325ffa8414cc2f52f599c18583618938a54c62df94638a8682f6e9c4337a1 + languageName: node + linkType: hard + "level-codec@npm:^9.0.0": version: 9.0.1 resolution: "level-codec@npm:9.0.1" @@ -8868,7 +9647,17 @@ fsevents@~2.1.2: languageName: node linkType: hard -"levn@npm:^0.3.0, levn@npm:~0.3.0": +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" + dependencies: + prelude-ls: ^1.2.1 + type-check: ~0.4.0 + checksum: 2f6ddfb0b956f2cb6b1608253a62b0c30e7392dd3c7b4cf284dfe2889b44d8385eaa81597646e253752c312a960ccb5e4d596968e476d5f6614f4ca60e5218e9 + languageName: node + linkType: hard + +"levn@npm:~0.3.0": version: 0.3.0 resolution: "levn@npm:0.3.0" dependencies: @@ -9224,14 +10013,14 @@ fsevents@~2.1.2: languageName: node linkType: hard -"lodash@npm:4.17.21": +"lodash@npm:4.17.21, lodash@npm:^4.17.20": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 4983720b9abca930a4a46f18db163d7dad8dd00dbed6db0cc7b499b33b717cce69f80928b27bbb1ff2cbd3b19d251ee90669a8b5ea466072ca81c2ebe91e7468 languageName: node linkType: hard -"lodash@npm:^4.11.2, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.2.1": +"lodash@npm:^4.11.2, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.15, lodash@npm:^4.2.1": version: 4.17.19 resolution: "lodash@npm:4.17.19" checksum: ff2b7a95f0129dba9101e346d44e0eda0f159d76bbbf23721eec1969b87a32bde3de0cfef0733218c64620e9be08040a973278d46a686540233b356115f3527c @@ -9283,6 +10072,17 @@ fsevents@~2.1.2: languageName: node linkType: hard +"loose-envify@npm:^1.4.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: ^3.0.0 || ^4.0.0 + bin: + loose-envify: cli.js + checksum: 5c3b47bbe5f597a3889fb001a3a98aaea2a3fafa48089c19034de1e0121bf57dbee609d184478514d74d5c5a7e9cfa3d846343455e5123b060040d46c39e91dc + languageName: node + linkType: hard + "loud-rejection@npm:^1.0.0": version: 1.6.0 resolution: "loud-rejection@npm:1.6.0" @@ -9530,6 +10330,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"merge2@npm:^1.3.0": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 7ad40d8b140a5ed4e621b916858410e4f0dd4ced1e5a2b675563347e70f0661d95ba6c3c8007dd3c4e242d0b8eee44559fa75bb90a146cf168debffc0cbc18f3 + languageName: node + linkType: hard + "methods@npm:^1.1.2, methods@npm:~1.1.2": version: 1.1.2 resolution: "methods@npm:1.1.2" @@ -10115,7 +10922,7 @@ fsevents@~2.1.2: languageName: node linkType: hard -"object-assign@npm:^4, object-assign@npm:^4.0.1, object-assign@npm:^4.1.0": +"object-assign@npm:^4, object-assign@npm:^4.0.1, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: 66cf021898fc1b13ea573ea8635fbd5a76533f50cecbc2fcd5eee1e8029af41bcebe7023788b6d0e06cbe4401ecea075d972f78ec74467cdc571a0f1a4d1a081 @@ -10147,6 +10954,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"object-inspect@npm:^1.9.0": + version: 1.9.0 + resolution: "object-inspect@npm:1.9.0" + checksum: 63b412167d716e332b3233090a9e8cc7951479a6971629fb8a3d00135a2329136c697fbd2f56e48bb132928f01bd0f8c5fe2d7386222f217228ca697b8c3932a + languageName: node + linkType: hard + "object-keys@npm:^1.0.11, object-keys@npm:^1.0.12, object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" @@ -10175,6 +10989,42 @@ fsevents@~2.1.2: languageName: node linkType: hard +"object.assign@npm:^4.1.2": + version: 4.1.2 + resolution: "object.assign@npm:4.1.2" + dependencies: + call-bind: ^1.0.0 + define-properties: ^1.1.3 + has-symbols: ^1.0.1 + object-keys: ^1.1.1 + checksum: a5855cc6db3f64606c41ceb97cb9847e667d8240889d771d65638244be1d35c2e2ccb5762f437bb76abf4e98ab4634a9d302380398121cee288a44dce5028f54 + languageName: node + linkType: hard + +"object.entries@npm:^1.1.2": + version: 1.1.3 + resolution: "object.entries@npm:1.1.3" + dependencies: + call-bind: ^1.0.0 + define-properties: ^1.1.3 + es-abstract: ^1.18.0-next.1 + has: ^1.0.3 + checksum: 89eec6d43bf8440dfd800ad76486d76a900ff7e3e20b560abb4cba8494bdc8524af8cf49a897739da776fe434f8091569b2422333075378f9fd5a50d599601eb + languageName: node + linkType: hard + +"object.fromentries@npm:^2.0.2": + version: 2.0.4 + resolution: "object.fromentries@npm:2.0.4" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + es-abstract: ^1.18.0-next.2 + has: ^1.0.3 + checksum: 9e02d109f6f63dda78715e43fcbd80941491e56ee771a5d21da93e271859f43b0db15e26e0b945989a6a6ee0ba480ca57b047cd331a71e4c4251d44517e0649c + languageName: node + linkType: hard + "object.getownpropertydescriptors@npm:^2.0.3": version: 2.0.3 resolution: "object.getownpropertydescriptors@npm:2.0.3" @@ -10206,6 +11056,18 @@ fsevents@~2.1.2: languageName: node linkType: hard +"object.values@npm:^1.1.1": + version: 1.1.3 + resolution: "object.values@npm:1.1.3" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + es-abstract: ^1.18.0-next.2 + has: ^1.0.3 + checksum: 31111fe8b8dfe7c3326ae8729eae542dc32d5705339b9b63d89d4a2f766641bfe8989744bd4771c65a7ca0dff281800e99640262c2e82daa97079143a86b3e0b + languageName: node + linkType: hard + "octokit-pagination-methods@npm:^1.1.0": version: 1.1.0 resolution: "octokit-pagination-methods@npm:1.1.0" @@ -10265,7 +11127,7 @@ fsevents@~2.1.2: languageName: node linkType: hard -"optionator@npm:^0.8.1, optionator@npm:^0.8.3": +"optionator@npm:^0.8.1": version: 0.8.3 resolution: "optionator@npm:0.8.3" dependencies: @@ -10279,6 +11141,20 @@ fsevents@~2.1.2: languageName: node linkType: hard +"optionator@npm:^0.9.1": + version: 0.9.1 + resolution: "optionator@npm:0.9.1" + dependencies: + deep-is: ^0.1.3 + fast-levenshtein: ^2.0.6 + levn: ^0.4.1 + prelude-ls: ^1.2.1 + type-check: ^0.4.0 + word-wrap: ^1.2.3 + checksum: bdf5683f986d00e173e6034837b7b6a9e68c7e1a37d7684b240adf1758db9076cfb04c9f64be29327881bb06c5017afb8b65012c5f02d07b180e9f6f42595ffd + languageName: node + linkType: hard + "os-homedir@npm:^1.0.0": version: 1.0.2 resolution: "os-homedir@npm:1.0.2" @@ -10755,6 +11631,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"prelude-ls@npm:^1.2.1": + version: 1.2.1 + resolution: "prelude-ls@npm:1.2.1" + checksum: bc1649f521e8928cde0e1b349b224de2e6f00b71361a4a44f2e4a615342b6e1ae30366c32d26412dabe74d999a40f79c0ae044ae6b17cf19af935e74d12ea4fa + languageName: node + linkType: hard + "prelude-ls@npm:~1.1.2": version: 1.1.2 resolution: "prelude-ls@npm:1.1.2" @@ -10771,12 +11654,12 @@ fsevents@~2.1.2: languageName: node linkType: hard -"prettier@npm:1.19.1": - version: 1.19.1 - resolution: "prettier@npm:1.19.1" +"prettier@npm:2.2.1": + version: 2.2.1 + resolution: "prettier@npm:2.2.1" bin: - prettier: ./bin-prettier.js - checksum: e5fcdfe5e159ef5c5480245353cf8fb5bbd1b8afff266f31f281641825238f8a645e58472f77cd75a09ccc45d44c335466e8d901ec138c2bda05e1bd6ea1077c + prettier: bin-prettier.js + checksum: 92c6c9f4b87eba1f28466edee57dd18c80d00b858edda77d46d1950d20e6e302b68ee255fc91133ba931e63c4577b5ae30da194d9626a8f3c0177778b91bf056 languageName: node linkType: hard @@ -10847,6 +11730,17 @@ fsevents@~2.1.2: languageName: node linkType: hard +"prop-types@npm:^15.7.2": + version: 15.7.2 + resolution: "prop-types@npm:15.7.2" + dependencies: + loose-envify: ^1.4.0 + object-assign: ^4.1.1 + react-is: ^16.8.1 + checksum: a440dd406c5cf53bf39f3e898d2c65178511d34ca3c8c789b30c177992408b9e4273969726b274719aa69ccce5ab34b2fd8caa60b90f23cd2e910cdcf682de52 + languageName: node + linkType: hard + "propagate@npm:^2.0.0": version: 2.0.1 resolution: "propagate@npm:2.0.1" @@ -10964,6 +11858,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"queue-microtask@npm:^1.2.2": + version: 1.2.2 + resolution: "queue-microtask@npm:1.2.2" + checksum: 563abf1b1d0916842c017a4c0784fffebd0dd7d5685ffd65356dfee8f084e34e2a9b449aa788dddb2767f7dc79d1834545bb75f8f643b8aa85aea20a9efabbec + languageName: node + linkType: hard + "quick-lru@npm:^1.0.0": version: 1.1.0 resolution: "quick-lru@npm:1.1.0" @@ -10997,7 +11898,7 @@ fsevents@~2.1.2: languageName: node linkType: hard -"react-is@npm:^16.12.0": +"react-is@npm:^16.12.0, react-is@npm:^16.8.1": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: 11bcf1267a314a522615f626f3ce3727a3a24cdbf61c4d452add3550a7875326669631326cfb1ba3e92b6f72244c32ffecf93ad21c0cad8455d3e169d0e3f060 @@ -11257,10 +12158,13 @@ fsevents@~2.1.2: languageName: node linkType: hard -"regexpp@npm:^2.0.1": - version: 2.0.1 - resolution: "regexpp@npm:2.0.1" - checksum: e537f6c1b59f31a8d6381c64408d7a852aa98794896702fdadef2fa8b049f7d876da30cd0c6f6a64488aa58ad3b225d606cc689059628056b5a593e5422c38d6 +"regexp.prototype.flags@npm:^1.3.1": + version: 1.3.1 + resolution: "regexp.prototype.flags@npm:1.3.1" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + checksum: 967e462a83cdfd6f226aa9337bda6f739e3fba72a49f3d3f4ed16b60d5a811ba576ef22f01e37b9230022ba715c6207c082ca117160b304b6503e4a6557628f5 languageName: node linkType: hard @@ -11271,6 +12175,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"regexpp@npm:^3.1.0": + version: 3.1.0 + resolution: "regexpp@npm:3.1.0" + checksum: 69d0ce6b449cf35d3732d6341a1e70850360ffc619f8eef10629871c462e614853fffb80d3f00fc17cd0bb5b8f34b0cde5be4b434e72c0eb3fbba2360c8b5ac4 + languageName: node + linkType: hard + "regexpu-core@npm:^4.7.0": version: 4.7.0 resolution: "regexpu-core@npm:4.7.0" @@ -11434,6 +12345,13 @@ fsevents@~2.1.2: languageName: node linkType: hard +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: 74fc30353e5d526879b28d480c3f25ca95e9c22dfe7ac10ca0650e03407b3aeed352ff8ca706ea145617b6482a582e4a3bd65a884fc50133ebe586d47fa085c6 + languageName: node + linkType: hard + "require-main-filename@npm:^2.0.0": version: 2.0.0 resolution: "require-main-filename@npm:2.0.0" @@ -11512,7 +12430,7 @@ resolve@1.1.7: languageName: node linkType: hard -resolve@^1.14.2: +"resolve@^1.13.1, resolve@^1.14.2, resolve@^1.18.1": version: 1.20.0 resolution: "resolve@npm:1.20.0" dependencies: @@ -11547,7 +12465,7 @@ resolve@^1.14.2: languageName: node linkType: hard -"resolve@patch:resolve@^1.14.2#builtin": +"resolve@patch:resolve@^1.13.1#builtin, resolve@patch:resolve@^1.14.2#builtin, resolve@patch:resolve@^1.18.1#builtin": version: 1.20.0 resolution: "resolve@patch:resolve@npm%3A1.20.0#builtin::version=1.20.0&hash=3388aa" dependencies: @@ -11584,14 +12502,10 @@ resolve@^1.14.2: languageName: node linkType: hard -"rimraf@npm:2.6.3, rimraf@npm:^2.2.8, rimraf@npm:^2.5.2, rimraf@npm:^2.6.3": - version: 2.6.3 - resolution: "rimraf@npm:2.6.3" - dependencies: - glob: ^7.1.3 - bin: - rimraf: ./bin.js - checksum: c9ce1854f19327606934558f4729b0f7aa7b9f1a3e7ca292d56261cce1074e20b0a0b16689166da6d8ab24ed9c30f7c71fba0df38e1d37f0233b6f48307c5c7a +"reusify@npm:^1.0.4": + version: 1.0.4 + resolution: "reusify@npm:1.0.4" + checksum: 08ef02ed0514f020a51131ba2e6c27c66ccebe25d49cfc83467a0d4054db4634a2853480d0895c710b645ab66af1a6fb3e183888306ae559413bd96c69f39ccd languageName: node linkType: hard @@ -11606,6 +12520,17 @@ resolve@^1.14.2: languageName: node linkType: hard +"rimraf@npm:^2.2.8, rimraf@npm:^2.5.2, rimraf@npm:^2.6.3": + version: 2.6.3 + resolution: "rimraf@npm:2.6.3" + dependencies: + glob: ^7.1.3 + bin: + rimraf: ./bin.js + checksum: c9ce1854f19327606934558f4729b0f7aa7b9f1a3e7ca292d56261cce1074e20b0a0b16689166da6d8ab24ed9c30f7c71fba0df38e1d37f0233b6f48307c5c7a + languageName: node + linkType: hard + "rimraf@npm:~2.4.0": version: 2.4.5 resolution: "rimraf@npm:2.4.5" @@ -11624,15 +12549,6 @@ resolve@^1.14.2: languageName: node linkType: hard -"run-async@npm:^2.2.0": - version: 2.3.0 - resolution: "run-async@npm:2.3.0" - dependencies: - is-promise: ^2.1.0 - checksum: a488425557ecbcd415e250b9b103c57feb4790b1b585607aad5d3f58c3a2f3fdaaa551c0f14d46b046324f7eaa5f7bc2e7dea08fb0c9717c5587d80595045a81 - languageName: node - linkType: hard - "run-async@npm:^2.4.0": version: 2.4.1 resolution: "run-async@npm:2.4.1" @@ -11649,6 +12565,15 @@ resolve@^1.14.2: languageName: node linkType: hard +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: ^1.2.2 + checksum: 3d12f0251ad043ed52689523b1e5fa5b7e5395a6ae0d2cbfb880a3009bb297de6d7e96ba4ad5a818e2722b42cea78a5ee6842d6d864736a7ca755ec119ed097c + languageName: node + linkType: hard + "rxjs@npm:^6.3.3": version: 6.5.2 resolution: "rxjs@npm:6.5.2" @@ -11786,7 +12711,7 @@ resolve@^1.14.2: languageName: node linkType: hard -"semver@npm:7.3.4": +"semver@npm:7.3.4, semver@npm:^7.2.1": version: 7.3.4 resolution: "semver@npm:7.3.4" dependencies: @@ -11924,6 +12849,17 @@ resolve@^1.14.2: languageName: node linkType: hard +"side-channel@npm:^1.0.4": + version: 1.0.4 + resolution: "side-channel@npm:1.0.4" + dependencies: + call-bind: ^1.0.0 + get-intrinsic: ^1.0.2 + object-inspect: ^1.9.0 + checksum: 84258ce3edb1ad35810ca17eccd52fd504b5d4da59447a6829cfd1ae8e3cff97b7df2a14f9a45b7aaa3b507ded95626cf20a500735d3b797e9ffb1eba3cfa9e7 + languageName: node + linkType: hard + "signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2": version: 3.0.2 resolution: "signal-exit@npm:3.0.2" @@ -11968,14 +12904,14 @@ resolve@^1.14.2: languageName: node linkType: hard -"slice-ansi@npm:^2.1.0": - version: 2.1.0 - resolution: "slice-ansi@npm:2.1.0" +"slice-ansi@npm:^4.0.0": + version: 4.0.0 + resolution: "slice-ansi@npm:4.0.0" dependencies: - ansi-styles: ^3.2.0 - astral-regex: ^1.0.0 - is-fullwidth-code-point: ^2.0.0 - checksum: 7578393cac91c28f8cb5fa5df36b826ad62c9e66313d2547770db8401570fa8f4aa20cd84ef9244fa054d8e9cc6bfc02578784bb89b238d384b99f2728a35a6d + ansi-styles: ^4.0.0 + astral-regex: ^2.0.0 + is-fullwidth-code-point: ^3.0.0 + checksum: f411aa051802605c3dc8523edee42d39ef59d7c36e6bef6bf1e61d9d2a83894187f6af56911a43ec8e58b921996722d75b354a4c3050b924426ffd1b05da33f9 languageName: node linkType: hard @@ -12286,17 +13222,6 @@ resolve@^1.14.2: languageName: node linkType: hard -"string-width@npm:^3.0.0": - version: 3.1.0 - resolution: "string-width@npm:3.1.0" - dependencies: - emoji-regex: ^7.0.1 - is-fullwidth-code-point: ^2.0.0 - strip-ansi: ^5.1.0 - checksum: 54c5d1842dc122d8e0251ad50e00e91c06368f1aca44f41a67cd5ce013c4ba8f5a26f1b7f72a3e1644f38c62092a82c86b646aff514073894faf84b9564a38a0 - languageName: node - linkType: hard - "string-width@npm:^4.1.0, string-width@npm:^4.2.0": version: 4.2.0 resolution: "string-width@npm:4.2.0" @@ -12308,6 +13233,31 @@ resolve@^1.14.2: languageName: node linkType: hard +"string.prototype.matchall@npm:^4.0.2": + version: 4.0.4 + resolution: "string.prototype.matchall@npm:4.0.4" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + es-abstract: ^1.18.0-next.2 + has-symbols: ^1.0.1 + internal-slot: ^1.0.3 + regexp.prototype.flags: ^1.3.1 + side-channel: ^1.0.4 + checksum: e19b26a14adc6f6957248ae0ce3a054ddfb5b783b7528a9dd7ee2635d95a977486805c7b2182dca17fd60e1a40e1be1e02f0a9fee32e19c29d2f1850564d96d1 + languageName: node + linkType: hard + +"string.prototype.trimend@npm:^1.0.4": + version: 1.0.4 + resolution: "string.prototype.trimend@npm:1.0.4" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + checksum: ea8793bee1104362587e6a0fab2cb48e76548423d8ac95847284f9f6ef6a11338cf47114e8ec1c2a9519cce55cfa8d19fc8e26413937c3e804a768ec43ebe38e + languageName: node + linkType: hard + "string.prototype.trimleft@npm:^2.0.0": version: 2.0.0 resolution: "string.prototype.trimleft@npm:2.0.0" @@ -12328,6 +13278,16 @@ resolve@^1.14.2: languageName: node linkType: hard +"string.prototype.trimstart@npm:^1.0.4": + version: 1.0.4 + resolution: "string.prototype.trimstart@npm:1.0.4" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.3 + checksum: dd2c994af9b9194c7ce9d94e30b8f8bbe30ec95ada94534a71d63df2964a200c8d2264378252a5047a5f1cf805e8216911d78d16b22d5db7b0abcdbbb2d24b4a + languageName: node + linkType: hard + "string_decoder@npm:^1.1.1": version: 1.2.0 resolution: "string_decoder@npm:1.2.0" @@ -12382,7 +13342,7 @@ resolve@^1.14.2: languageName: node linkType: hard -"strip-ansi@npm:^5.1.0, strip-ansi@npm:^5.2.0": +"strip-ansi@npm:^5.2.0": version: 5.2.0 resolution: "strip-ansi@npm:5.2.0" dependencies: @@ -12464,10 +13424,10 @@ resolve@^1.14.2: languageName: node linkType: hard -"strip-json-comments@npm:^3.0.1": - version: 3.0.1 - resolution: "strip-json-comments@npm:3.0.1" - checksum: b783c8c9c18f5b8de69cf9600235adf11950051dc2ed28dabd05d8e17cd82e138df2dad635c205b3d7c068a644398099a8f1060cee39c93067ef2188dda791ef +"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: f16719ce25abc58a55ef82b1c27f541dcfa5d544f17158f62d10be21ff9bd22fde45a53c592b29d80ad3c97ccb67b7451c4833913fdaeadb508a40f5e0a9c206 languageName: node linkType: hard @@ -12563,15 +13523,15 @@ resolve@^1.14.2: languageName: node linkType: hard -"table@npm:^5.2.3": - version: 5.4.5 - resolution: "table@npm:5.4.5" +"table@npm:^6.0.4": + version: 6.0.7 + resolution: "table@npm:6.0.7" dependencies: - ajv: ^6.10.2 - lodash: ^4.17.14 - slice-ansi: ^2.1.0 - string-width: ^3.0.0 - checksum: cade95335d8853d52c308393dda6dfc061c63ac136e068d5c45ffcac032e598ee0e814fabd88790ba59f07265e6cc649c5a6c5a7c62e6cfcb540e00deccede6d + ajv: ^7.0.2 + lodash: ^4.17.20 + slice-ansi: ^4.0.0 + string-width: ^4.2.0 + checksum: b28d81d6063110a8e94264ff17d3b7505fd344947f2c5cdf0fa71f7a622897fb15068686652d3aed8ed1c5817ca783be8a9c3419edf27808350ad29cc7d87fdf languageName: node linkType: hard @@ -12849,6 +13809,18 @@ resolve@^1.14.2: languageName: node linkType: hard +"tsconfig-paths@npm:^3.9.0": + version: 3.9.0 + resolution: "tsconfig-paths@npm:3.9.0" + dependencies: + "@types/json5": ^0.0.29 + json5: ^1.0.1 + minimist: ^1.2.0 + strip-bom: ^3.0.0 + checksum: 5383ba626b3ac70e08094b9dfd1e30ce82878407b6c8db8cd84279cc7c7340d5f53f67dbeb8174a233c082a068322a6b00ec8514b96d9a80a453e0476dc116d2 + languageName: node + linkType: hard + "tslib@npm:^1.8.1, tslib@npm:^1.9.0": version: 1.10.0 resolution: "tslib@npm:1.10.0" @@ -12890,6 +13862,15 @@ resolve@^1.14.2: languageName: node linkType: hard +"type-check@npm:^0.4.0, type-check@npm:~0.4.0": + version: 0.4.0 + resolution: "type-check@npm:0.4.0" + dependencies: + prelude-ls: ^1.2.1 + checksum: 6c2e1ce339567e122504f0c729cfa35d877fb2da293b99110f0819eca81e6ed8d3ba9bb36c0bc0ee4904d5340dbe678f8642a395c1c67b1d0f69f081efb47f4a + languageName: node + linkType: hard + "type-check@npm:~0.3.2": version: 0.3.2 resolution: "type-check@npm:0.3.2" @@ -12992,6 +13973,18 @@ typescript@3.9.9: languageName: node linkType: hard +"unbox-primitive@npm:^1.0.0": + version: 1.0.0 + resolution: "unbox-primitive@npm:1.0.0" + dependencies: + function-bind: ^1.1.1 + has-bigints: ^1.0.0 + has-symbols: ^1.0.0 + which-boxed-primitive: ^1.0.1 + checksum: 25e82f99bb40981f30615644305c757ecefff43d2ef2ac1b80e24f304f3002cd637eecb672bdd07f5fb858a265d96a4b2e983c714cba65498715acf7af23e86b + languageName: node + linkType: hard + "unbzip2-stream@npm:^1.3.3": version: 1.4.3 resolution: "unbzip2-stream@npm:1.4.3" @@ -13287,7 +14280,8 @@ typescript@3.9.9: "@types/node": 12.12.21 "@types/request": 2.48.3 "@types/semver": 6.2.0 - "@typescript-eslint/eslint-plugin": 2.12.0 + "@typescript-eslint/eslint-plugin": 4.13.0 + "@typescript-eslint/parser": 4.13.0 "@verdaccio/commons-api": 9.7.1 "@verdaccio/eslint-config": ^8.5.0 "@verdaccio/local-storage": 9.7.5 @@ -13314,7 +14308,17 @@ typescript@3.9.9: dayjs: 1.10.4 detect-secrets: 1.0.6 envinfo: 7.7.4 - eslint: 6.8.0 + eslint: 7.19.0 + eslint-config-google: 0.14.0 + eslint-config-prettier: 7.2.0 + eslint-plugin-babel: 5.3.1 + eslint-plugin-import: 2.22.1 + eslint-plugin-jest: 24.1.3 + eslint-plugin-jsx-a11y: 6.4.1 + eslint-plugin-react: 7.22.0 + eslint-plugin-react-hooks: 4.2.0 + eslint-plugin-simple-import-sort: 7.0.0 + eslint-plugin-verdaccio: 9.6.1 express: 4.17.1 fs-extra: 9.1.0 get-stdin: 7.0.0 @@ -13339,7 +14343,7 @@ typescript@3.9.9: mv: 2.1.1 nock: 12.0.3 pkginfo: 0.4.1 - prettier: 1.19.1 + prettier: 2.2.1 puppeteer: 5.5.0 request: 2.88.0 rimraf: 3.0.2 @@ -13432,6 +14436,19 @@ typescript@3.9.9: languageName: node linkType: hard +"which-boxed-primitive@npm:^1.0.1": + version: 1.0.2 + resolution: "which-boxed-primitive@npm:1.0.2" + dependencies: + is-bigint: ^1.0.1 + is-boolean-object: ^1.1.0 + is-number-object: ^1.0.4 + is-string: ^1.0.5 + is-symbol: ^1.0.3 + checksum: 771ef43357afbba9febf2da4867b2971ada0a5126227f9b7926751525e3721f7f5f3722f8c60af67881714d9a82a98ed686f1768490cfb2cd40518df5f2e056e + languageName: node + linkType: hard + "which-module@npm:^2.0.0": version: 2.0.0 resolution: "which-module@npm:2.0.0" @@ -13490,7 +14507,7 @@ typescript@3.9.9: languageName: node linkType: hard -"word-wrap@npm:~1.2.3": +"word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": version: 1.2.3 resolution: "word-wrap@npm:1.2.3" checksum: 6526abd75d4409c76d1989cf2fbf6080b903db29824be3d17d0a0b8f6221486c76a021174eda2616cf311199787983c34bae3c5e7b51d2ad7476f2066cddb75a @@ -13555,15 +14572,6 @@ typescript@3.9.9: languageName: node linkType: hard -"write@npm:1.0.3": - version: 1.0.3 - resolution: "write@npm:1.0.3" - dependencies: - mkdirp: ^0.5.1 - checksum: e8f8fddefea3eaaf4c8bacf072161f82d5e05c5fb8f003e1bae52673b94b88a4954d97688c7403a20301d2f6e9f61363b1affe74286b499b39bc0c42f17a56cb - languageName: node - linkType: hard - "ws@npm:^7.0.0": version: 7.2.1 resolution: "ws@npm:7.2.1"