mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-24 21:15:51 +01:00
refactor: test api refactor (#1826)
* test: add test for whoami * Update middleware.ts * test for user api * more test for user api * remove repeated code * refactor * Update index.spec.ts * add package test refactor others * chore: upgrade deps * chore: add test for package * chore: update test * update lock file * Update ci.yml * Update ci.yml * Update package.spec.ts * chore: update ci settings * chore: update deps * chore: update test
This commit is contained in:
parent
d3f78e5b34
commit
a7ba76423e
@ -13,6 +13,9 @@ Dockerfile
|
|||||||
*.html
|
*.html
|
||||||
*.scss
|
*.scss
|
||||||
*.png
|
*.png
|
||||||
|
*.json
|
||||||
|
*.name
|
||||||
|
*.tgz
|
||||||
*.jpg
|
*.jpg
|
||||||
*.sh
|
*.sh
|
||||||
**/partials/**
|
**/partials/**
|
||||||
|
99
.eslintrc
99
.eslintrc
@ -1,102 +1,21 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"@verdaccio"
|
||||||
"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": {
|
"rules": {
|
||||||
"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", 180],
|
|
||||||
"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-var-requires": 0,
|
||||||
|
"@typescript-eslint/ban-ts-ignore": 0,
|
||||||
"@typescript-eslint/no-inferrable-types": 0,
|
"@typescript-eslint/no-inferrable-types": 0,
|
||||||
"@typescript-eslint/no-empty-function": 0,
|
"@typescript-eslint/no-empty-function": 0,
|
||||||
"@typescript-eslint/no-this-alias": 0,
|
"@typescript-eslint/no-this-alias": ["warn"],
|
||||||
"@typescript-eslint/no-use-before-define": 0,
|
"@typescript-eslint/no-use-before-define": 0,
|
||||||
"@typescript-eslint/array-type": ["error"],
|
"@typescript-eslint/array-type": ["warn"],
|
||||||
"@typescript-eslint/no-explicit-any": 0,
|
"@typescript-eslint/no-explicit-any": 0,
|
||||||
"@typescript-eslint/indent": 0,
|
"@typescript-eslint/indent": 0,
|
||||||
"@typescript-eslint/ban-ts-comment": 0,
|
"@typescript-eslint/interface-name-prefix": 0,
|
||||||
"@typescript-eslint/ban-types": 0,
|
"import/order": 0,
|
||||||
"@typescript-eslint/explicit-module-boundary-types": 0,
|
"handle-callback-err": 1,
|
||||||
|
"prefer-const": 1,
|
||||||
// rules to fix
|
"prefer-promise-reject-errors": 1
|
||||||
"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"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -1,6 +1,16 @@
|
|||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- .github/workflows/ci.yml
|
||||||
|
- 'packages/**'
|
||||||
|
- 'jest/**'
|
||||||
|
- 'package.json'
|
||||||
|
- 'lerna.json'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
name: Docker & Publish Pre-check
|
name: Docker & Publish Pre-check
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'packages/**'
|
|
||||||
- 'docker-bin/**'
|
|
||||||
- 'package.json'
|
|
||||||
- 'lerna.json'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/docker-publish-pre-check.yml
|
- .github/workflows/docker-publish-pre-check.yml
|
||||||
|
2
.github/workflows/docker-publish.yml
vendored
2
.github/workflows/docker-publish.yml
vendored
@ -2,6 +2,8 @@ name: Docker publish to GitHub registry
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/docker-publish.yml
|
- .github/workflows/docker-publish.yml
|
||||||
- 'packages/**'
|
- 'packages/**'
|
||||||
|
23
debug/DEBUGGING.md
Normal file
23
debug/DEBUGGING.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Debuging Documentation
|
||||||
|
|
||||||
|
|
||||||
|
## Debugging tests
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Running a single test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test test/integration/package.spec.ts --runInBand
|
||||||
|
```
|
||||||
|
|
||||||
|
Using `--runInBand` allows you to see the `console.log` prints, without that `jest` hidde them.
|
||||||
|
|
||||||
|
#### Display additional information
|
||||||
|
|
||||||
|
You can take advance of `debug` module used by many dependencies, eg:
|
||||||
|
|
||||||
|
* `supertest`: `DEBUG=superagent yarn test test/integration/package.spec.ts --runInBand`
|
||||||
|
* `express`: `DEBUG=express:* yarn test test/integration/package.spec.ts --runInBand`
|
||||||
|
* `nock`: `DEBUG=nock yarn test test/integration/package.spec.ts --runInBand`
|
||||||
|
* All of if: `DEBUG=* yarn test test/integration/package.spec.ts --runInBand`
|
39
package.json
39
package.json
@ -21,18 +21,19 @@
|
|||||||
"@commitlint/cli": "8.3.5",
|
"@commitlint/cli": "8.3.5",
|
||||||
"@commitlint/config-conventional": "8.2.0",
|
"@commitlint/config-conventional": "8.2.0",
|
||||||
"@octokit/rest": "17.0.0",
|
"@octokit/rest": "17.0.0",
|
||||||
"@types/async": "3.0.3",
|
"@types/async": "3.2.3",
|
||||||
"@types/express": "4.17.1",
|
"@types/express": "4.17.6",
|
||||||
"@types/http-errors": "1.6.3",
|
"@types/http-errors": "1.6.3",
|
||||||
"@types/jest": "25.2.3",
|
"@types/jest": "26.0.1",
|
||||||
"@types/lodash": "4.14.151",
|
"@types/lodash": "4.14.156",
|
||||||
"@types/mime": "2.0.2",
|
"@types/mime": "2.0.2",
|
||||||
"@types/minimatch": "3.0.3",
|
"@types/minimatch": "3.0.3",
|
||||||
"@types/node": "12.12.21",
|
"@types/node": "14.0.14",
|
||||||
"@types/request": "2.48.3",
|
"@types/request": "2.48.3",
|
||||||
"@types/semver": "7.2.0",
|
"@types/semver": "7.2.0",
|
||||||
"@verdaccio/babel-preset": "9.4.0",
|
"@types/supertest": "2.0.9",
|
||||||
"@verdaccio/eslint-config": "9.0.0",
|
"@verdaccio/babel-preset": "9.6.1",
|
||||||
|
"@verdaccio/eslint-config": "9.3.2",
|
||||||
"@verdaccio/types": "9.5.0",
|
"@verdaccio/types": "9.5.0",
|
||||||
"codecov": "3.6.1",
|
"codecov": "3.6.1",
|
||||||
"cross-env": "7.0.2",
|
"cross-env": "7.0.2",
|
||||||
@ -42,22 +43,22 @@
|
|||||||
"get-stdin": "7.0.0",
|
"get-stdin": "7.0.0",
|
||||||
"husky": "2.7.0",
|
"husky": "2.7.0",
|
||||||
"in-publish": "2.0.0",
|
"in-publish": "2.0.0",
|
||||||
"jest": "26.0.1",
|
"jest": "26.1.0",
|
||||||
"jest-environment-node": "26.0.1",
|
"jest-environment-node": "26.1.0",
|
||||||
"jest-junit": "10.0.0",
|
"jest-junit": "11.0.1",
|
||||||
"kleur": "3.0.3",
|
"kleur": "3.0.3",
|
||||||
"lerna": "3.21.0",
|
"lerna": "3.22.1",
|
||||||
"lint-staged": "8.2.1",
|
"lint-staged": "8.2.1",
|
||||||
"nock": "11.7.2",
|
"nock": "12.0.3",
|
||||||
"prettier": "1.19.1",
|
"prettier": "1.19.1",
|
||||||
"rimraf": "3.0.0",
|
"rimraf": "3.0.2",
|
||||||
"selfsigned": "1.10.7",
|
"selfsigned": "1.10.7",
|
||||||
"standard-version": "7.0.1",
|
"standard-version": "8.0.0",
|
||||||
"supertest": "4.0.2",
|
"supertest": "4.0.2",
|
||||||
"typescript": "3.9.2",
|
"typescript": "3.9.5",
|
||||||
"verdaccio": "4.6.2",
|
"verdaccio": "4.7.1",
|
||||||
"verdaccio-auth-memory": "9.3.0",
|
"verdaccio-auth-memory": "9.7.0",
|
||||||
"verdaccio-memory": "9.3.0"
|
"verdaccio-memory": "9.7.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bootstrap": "lerna bootstrap",
|
"bootstrap": "lerna bootstrap",
|
||||||
@ -73,7 +74,7 @@
|
|||||||
"release:prerelease": "lerna version --conventional-commits --conventional-prerelease --preid next --registry http://localhost:4873",
|
"release:prerelease": "lerna version --conventional-commits --conventional-prerelease --preid next --registry http://localhost:4873",
|
||||||
"release:publish": "lerna publish from-git",
|
"release:publish": "lerna publish from-git",
|
||||||
"release:publish-prerelease": "lerna publish from-git --pre-dist-tag next",
|
"release:publish-prerelease": "lerna publish from-git --pre-dist-tag next",
|
||||||
"lint": "eslint \"packages/**/@(src|tests)/**\"",
|
"lint": "eslint \"packages/**/@(src|tests|test)/**\"",
|
||||||
"test": "lerna run test --concurrency 1",
|
"test": "lerna run test --concurrency 1",
|
||||||
"test:e2e:cli": "cross-env NODE_ENV=test jest --config ./test/e2e-cli/jest.config.e2e.cli.js --passWithNoTests",
|
"test:e2e:cli": "cross-env NODE_ENV=test jest --config ./test/e2e-cli/jest.config.e2e.cli.js --passWithNoTests",
|
||||||
"website:lint": "cd website && yarn lint",
|
"website:lint": "cd website && yarn lint",
|
||||||
|
19
packages/api/__mocks__/@verdaccio/logger/index.js
Normal file
19
packages/api/__mocks__/@verdaccio/logger/index.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const setup = jest.fn();
|
||||||
|
const logger = {
|
||||||
|
child: jest.fn(() => ({
|
||||||
|
debug: jest.fn(),
|
||||||
|
trace: jest.fn(),
|
||||||
|
warn: jest.fn(),
|
||||||
|
info: jest.fn(),
|
||||||
|
error: jest.fn(),
|
||||||
|
fatal: jest.fn(),
|
||||||
|
})),
|
||||||
|
debug: jest.fn(),
|
||||||
|
trace: jest.fn(),
|
||||||
|
warn: jest.fn(),
|
||||||
|
info: jest.fn(),
|
||||||
|
error: jest.fn(),
|
||||||
|
fatal: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
export { setup, logger }
|
@ -24,11 +24,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/auth": "5.0.0-alpha.0",
|
"@verdaccio/auth": "5.0.0-alpha.0",
|
||||||
"@verdaccio/commons-api": "9.4.0",
|
"@verdaccio/commons-api": "9.6.1",
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"@verdaccio/hooks": "5.0.0-alpha.0",
|
"@verdaccio/hooks": "5.0.0-alpha.0",
|
||||||
"@verdaccio/logger": "5.0.0-alpha.0",
|
"@verdaccio/logger": "5.0.0-alpha.0",
|
||||||
"@verdaccio/middleware": "5.0.0-alpha.0",
|
"@verdaccio/middleware": "5.0.0-alpha.0",
|
||||||
|
"@verdaccio/store": "5.0.0-alpha.0",
|
||||||
"@verdaccio/utils": "5.0.0-alpha.0",
|
"@verdaccio/utils": "5.0.0-alpha.0",
|
||||||
"body-parser": "1.19.0",
|
"body-parser": "1.19.0",
|
||||||
"cookies": "0.8.0",
|
"cookies": "0.8.0",
|
||||||
@ -38,7 +39,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@verdaccio/dev-types": "5.0.0-alpha.0",
|
"@verdaccio/dev-types": "5.0.0-alpha.0",
|
||||||
"@verdaccio/types": "9.3.0"
|
"@verdaccio/types": "9.5.0",
|
||||||
|
"express": "4.17.1"
|
||||||
},
|
},
|
||||||
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ export default function(config: Config, auth: IAuth, storage: IStorageHandler):
|
|||||||
app.param('_rev', match(/^-rev$/));
|
app.param('_rev', match(/^-rev$/));
|
||||||
app.param('org_couchdb_user', match(/^org\.couchdb\.user:/));
|
app.param('org_couchdb_user', match(/^org\.couchdb\.user:/));
|
||||||
app.param('anything', match(/.*/));
|
app.param('anything', match(/.*/));
|
||||||
|
|
||||||
app.use(auth.apiJWTmiddleware());
|
app.use(auth.apiJWTmiddleware());
|
||||||
app.use(bodyParser.json({ strict: false, limit: config.max_body_size || '10mb' }));
|
app.use(bodyParser.json({ strict: false, limit: config.max_body_size || '10mb' }));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -15,7 +15,7 @@ const downloadStream = (packageName: string, filename: string, storage: any, req
|
|||||||
});
|
});
|
||||||
|
|
||||||
stream.on('error', function(err): void {
|
stream.on('error', function(err): void {
|
||||||
return res.report_error(err);
|
return res.locals.report_error(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
res.header(HEADERS.CONTENT_TYPE, HEADERS.OCTET_STREAM);
|
res.header(HEADERS.CONTENT_TYPE, HEADERS.OCTET_STREAM);
|
||||||
|
@ -139,7 +139,7 @@ export function publishPackage(storage: IStorageHandler, config: Config, auth: I
|
|||||||
storage.mergeTags(packageName, tags, cb);
|
storage.mergeTags(packageName, tags, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
const afterChange = function(error, okMessage, metadata): void {
|
const afterChange = function(error, okMessage, metadata: Package): void {
|
||||||
const metadataCopy: Package = { ...metadata };
|
const metadataCopy: Package = { ...metadata };
|
||||||
|
|
||||||
const { _attachments, versions } = metadataCopy;
|
const { _attachments, versions } = metadataCopy;
|
||||||
@ -326,7 +326,7 @@ export function uploadPackageTarball(storage: IStorageHandler) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
stream.on('error', function(err) {
|
stream.on('error', function(err) {
|
||||||
return res.report_error(err);
|
return res.locals.report_error(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.on('success', function() {
|
stream.on('success', function() {
|
||||||
|
@ -74,16 +74,4 @@ export default function(route: Router, auth: IAuth, config: Config): void {
|
|||||||
ok: API_MESSAGE.LOGGED_OUT,
|
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());
|
|
||||||
|
|
||||||
next({
|
|
||||||
ok: true,
|
|
||||||
name: 'somebody',
|
|
||||||
roles: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
8
packages/api/test/.eslintrc
Normal file
8
packages/api/test/.eslintrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/explicit-function-return-type": 0,
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": 0,
|
||||||
|
"@typescript-eslint/no-unused-vars": 2,
|
||||||
|
"no-console": 0
|
||||||
|
}
|
||||||
|
}
|
70
packages/api/test/integration/_helper.ts
Normal file
70
packages/api/test/integration/_helper.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import path from "path";
|
||||||
|
import express, {Application} from 'express';
|
||||||
|
import supertest from 'supertest';
|
||||||
|
|
||||||
|
import {parseConfigFile} from '@verdaccio/utils';
|
||||||
|
import { Config } from '@verdaccio/config';
|
||||||
|
import { Storage } from '@verdaccio/store';
|
||||||
|
import { final, handleError, errorReportingMiddleware } from '@verdaccio/middleware';
|
||||||
|
import { Auth } from '@verdaccio/auth';
|
||||||
|
import apiEndpoints from '../../src';
|
||||||
|
import {IAuth} from "@verdaccio/dev-types";
|
||||||
|
import {HEADER_TYPE, HTTP_STATUS, generatePackageMetadata} from "@verdaccio/dev-commons";
|
||||||
|
import {HEADERS} from "@verdaccio/commons-api";
|
||||||
|
|
||||||
|
const getConf = (conf) => {
|
||||||
|
const configPath = path.join(__dirname, 'config', conf);
|
||||||
|
|
||||||
|
return parseConfigFile(configPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function initializeServer(configName): Promise<Application> {
|
||||||
|
const app = express();
|
||||||
|
const config = new Config(getConf(configName));
|
||||||
|
const storage = new Storage(config);
|
||||||
|
await storage.init(config, []);
|
||||||
|
const auth: IAuth = new Auth(config);
|
||||||
|
// @ts-ignore
|
||||||
|
app.use(errorReportingMiddleware);
|
||||||
|
// @ts-ignore
|
||||||
|
app.use(apiEndpoints(config, auth, storage));
|
||||||
|
// @ts-ignore
|
||||||
|
app.use(handleError);
|
||||||
|
// @ts-ignore
|
||||||
|
app.use(final);
|
||||||
|
|
||||||
|
app.use(function(request, response) {
|
||||||
|
response.status(590);
|
||||||
|
console.log('respo', response);
|
||||||
|
response.json({error: 'cannot handle this'});
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function publishVersion(app, configFile, pkgName, version): supertest.Test {
|
||||||
|
const pkgMetadata = generatePackageMetadata(pkgName, version);
|
||||||
|
|
||||||
|
return supertest(app)
|
||||||
|
.put(`/${encodeURIComponent(pkgName)}`)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.send(JSON.stringify(pkgMetadata))
|
||||||
|
.set('accept', HEADERS.GZIP)
|
||||||
|
.set(HEADER_TYPE.ACCEPT_ENCODING, HEADERS.JSON)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function publishTaggedVersion(app, configFile, pkgName: string, version: string, tag: string) {
|
||||||
|
const pkgMetadata = generatePackageMetadata(pkgName, version, {
|
||||||
|
[tag]: version
|
||||||
|
});
|
||||||
|
|
||||||
|
return supertest(app)
|
||||||
|
.put(`/${encodeURIComponent(pkgName)}/${encodeURIComponent(version)}/-tag/${encodeURIComponent(tag)}`)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.send(JSON.stringify(pkgMetadata))
|
||||||
|
.expect(HTTP_STATUS.CREATED)
|
||||||
|
.set('accept', HEADERS.GZIP)
|
||||||
|
.set(HEADER_TYPE.ACCEPT_ENCODING, HEADERS.JSON)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
|
||||||
|
}
|
30
packages/api/test/integration/config/package.yaml
Normal file
30
packages/api/test/integration/config/package.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
store:
|
||||||
|
memory:
|
||||||
|
limit: 1000
|
||||||
|
|
||||||
|
auth:
|
||||||
|
auth-memory:
|
||||||
|
users:
|
||||||
|
test:
|
||||||
|
name: test
|
||||||
|
password: test
|
||||||
|
|
||||||
|
web:
|
||||||
|
enable: true
|
||||||
|
title: verdaccio
|
||||||
|
|
||||||
|
publish:
|
||||||
|
allow_offline: false
|
||||||
|
|
||||||
|
uplinks:
|
||||||
|
|
||||||
|
logs: { type: stdout, format: pretty, level: trace }
|
||||||
|
|
||||||
|
packages:
|
||||||
|
'@*/*':
|
||||||
|
access: $anonymous
|
||||||
|
publish: $anonymous
|
||||||
|
'**':
|
||||||
|
access: $anonymous
|
||||||
|
publish: $anonymous
|
||||||
|
_debug: true
|
30
packages/api/test/integration/config/ping.yaml
Normal file
30
packages/api/test/integration/config/ping.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
store:
|
||||||
|
memory:
|
||||||
|
limit: 10
|
||||||
|
|
||||||
|
auth:
|
||||||
|
auth-memory:
|
||||||
|
users:
|
||||||
|
web:
|
||||||
|
enable: true
|
||||||
|
title: verdaccio
|
||||||
|
|
||||||
|
uplinks:
|
||||||
|
|
||||||
|
logs: { type: stdout, format: pretty, level: trace }
|
||||||
|
|
||||||
|
packages:
|
||||||
|
'@*/*':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
unpublish: $all
|
||||||
|
proxy: npmjs
|
||||||
|
'verdaccio':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
'**':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
unpublish: $all
|
||||||
|
proxy: npmjs
|
||||||
|
_debug: true
|
30
packages/api/test/integration/config/publish.yaml
Normal file
30
packages/api/test/integration/config/publish.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
store:
|
||||||
|
memory:
|
||||||
|
limit: 1000
|
||||||
|
|
||||||
|
auth:
|
||||||
|
auth-memory:
|
||||||
|
users:
|
||||||
|
test:
|
||||||
|
name: test
|
||||||
|
password: test
|
||||||
|
|
||||||
|
web:
|
||||||
|
enable: true
|
||||||
|
title: verdaccio
|
||||||
|
|
||||||
|
publish:
|
||||||
|
allow_offline: false
|
||||||
|
|
||||||
|
uplinks:
|
||||||
|
|
||||||
|
logs: { type: stdout, format: pretty, level: trace }
|
||||||
|
|
||||||
|
packages:
|
||||||
|
'@*/*':
|
||||||
|
access: $anonymous
|
||||||
|
publish: $anonymous
|
||||||
|
'**':
|
||||||
|
access: $anonymous
|
||||||
|
publish: $anonymous
|
||||||
|
_debug: true
|
36
packages/api/test/integration/config/user.yaml
Normal file
36
packages/api/test/integration/config/user.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
store:
|
||||||
|
memory:
|
||||||
|
limit: 1000
|
||||||
|
|
||||||
|
auth:
|
||||||
|
auth-memory:
|
||||||
|
users:
|
||||||
|
test:
|
||||||
|
name: test
|
||||||
|
password: test
|
||||||
|
|
||||||
|
web:
|
||||||
|
enable: true
|
||||||
|
title: verdaccio
|
||||||
|
|
||||||
|
uplinks:
|
||||||
|
npmjs:
|
||||||
|
url: https://registry.npmjs.org/
|
||||||
|
|
||||||
|
logs: { type: stdout, format: pretty, level: trace }
|
||||||
|
|
||||||
|
packages:
|
||||||
|
'@*/*':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
unpublish: $all
|
||||||
|
proxy: npmjs
|
||||||
|
'verdaccio':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
'**':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
unpublish: $all
|
||||||
|
proxy: npmjs
|
||||||
|
_debug: true
|
36
packages/api/test/integration/config/whoami.yaml
Normal file
36
packages/api/test/integration/config/whoami.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
store:
|
||||||
|
memory:
|
||||||
|
limit: 1000
|
||||||
|
|
||||||
|
auth:
|
||||||
|
auth-memory:
|
||||||
|
users:
|
||||||
|
test:
|
||||||
|
name: test
|
||||||
|
password: test
|
||||||
|
|
||||||
|
web:
|
||||||
|
enable: true
|
||||||
|
title: verdaccio
|
||||||
|
|
||||||
|
uplinks:
|
||||||
|
npmjs:
|
||||||
|
url: https://registry.npmjs.org/
|
||||||
|
|
||||||
|
logs: { type: stdout, format: pretty, level: trace }
|
||||||
|
|
||||||
|
packages:
|
||||||
|
'@*/*':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
unpublish: $all
|
||||||
|
proxy: npmjs
|
||||||
|
'verdaccio':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
'**':
|
||||||
|
access: $all
|
||||||
|
publish: $all
|
||||||
|
unpublish: $all
|
||||||
|
proxy: npmjs
|
||||||
|
_debug: true
|
83
packages/api/test/integration/package.spec.ts
Normal file
83
packages/api/test/integration/package.spec.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import supertest from 'supertest';
|
||||||
|
|
||||||
|
import {initializeServer, publishTaggedVersion, publishVersion} from './_helper';
|
||||||
|
import { HTTP_STATUS } from '@verdaccio/commons-api';
|
||||||
|
import {HEADER_TYPE, HEADERS} from '@verdaccio/dev-commons';
|
||||||
|
import {$RequestExtend, $ResponseExtend} from "@verdaccio/dev-types";
|
||||||
|
|
||||||
|
const mockApiJWTmiddleware = jest.fn(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: 'foo', groups: [], real_groups: []}
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
jest.mock('@verdaccio/auth', () => ({
|
||||||
|
Auth: class {
|
||||||
|
apiJWTmiddleware() {
|
||||||
|
return mockApiJWTmiddleware();
|
||||||
|
}
|
||||||
|
allow_access (_d, f_, cb) {
|
||||||
|
cb(null, true)
|
||||||
|
}
|
||||||
|
allow_publish (_d, f_, cb) {
|
||||||
|
cb(null, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('package', () => {
|
||||||
|
let app;
|
||||||
|
beforeAll(async () => {
|
||||||
|
app = await initializeServer('package.yaml');
|
||||||
|
await publishVersion(app, 'package.yaml', 'foo', '1.0.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return a package', async (done) => {
|
||||||
|
|
||||||
|
return supertest(app)
|
||||||
|
.get('/foo')
|
||||||
|
.set('Accept', HEADERS.JSON)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.OK)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.body.name).toEqual('foo');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return a package by version', async (done) => {
|
||||||
|
return supertest(app)
|
||||||
|
.get('/foo/1.0.0')
|
||||||
|
.set('Accept', HEADERS.JSON)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.OK)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.body.name).toEqual('foo');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: investigate the 404
|
||||||
|
test.skip('should return a package by dist-tag', async (done) => {
|
||||||
|
await publishVersion(app, 'package.yaml', 'foo-tagged', '1.0.0');
|
||||||
|
await publishTaggedVersion(app, 'package.yaml', 'foo-tagged', '1.0.1', 'test');
|
||||||
|
return supertest(app)
|
||||||
|
.get('/foo-tagged/1.0.0')
|
||||||
|
.set('Accept', HEADERS.JSON)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.CREATED)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.body.name).toEqual('foo');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return 404', async () => {
|
||||||
|
return supertest(app)
|
||||||
|
.get('/404-not-found')
|
||||||
|
.set('Accept', HEADERS.JSON)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.NOT_FOUND);
|
||||||
|
});
|
||||||
|
});
|
16
packages/api/test/integration/ping.spec.ts
Normal file
16
packages/api/test/integration/ping.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import supertest from 'supertest';
|
||||||
|
|
||||||
|
import {initializeServer } from './_helper';
|
||||||
|
import { HTTP_STATUS } from '@verdaccio/commons-api';
|
||||||
|
import {HEADER_TYPE, HEADERS} from '@verdaccio/dev-commons';
|
||||||
|
|
||||||
|
describe('ping', () => {
|
||||||
|
test('should return the reply the ping', async () => {
|
||||||
|
return supertest(await initializeServer('ping.yaml'))
|
||||||
|
.get('/-/ping')
|
||||||
|
.set('Accept', HEADERS.JSON)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.OK)
|
||||||
|
.then(response => expect(response.body).toEqual({}));
|
||||||
|
});
|
||||||
|
});
|
179
packages/api/test/integration/publish.spec.ts
Normal file
179
packages/api/test/integration/publish.spec.ts
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
import {initializeServer, publishVersion} from './_helper';
|
||||||
|
import { HTTP_STATUS } from '@verdaccio/commons-api';
|
||||||
|
import {API_ERROR, API_MESSAGE, generatePackageMetadata, HEADER_TYPE, HEADERS} from '@verdaccio/dev-commons';
|
||||||
|
import {$RequestExtend, $ResponseExtend} from '@verdaccio/dev-types';
|
||||||
|
import supertest from "supertest";
|
||||||
|
|
||||||
|
const mockApiJWTmiddleware = jest.fn(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: 'foo', groups: [], real_groups: []}
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
jest.setTimeout(50000000);
|
||||||
|
|
||||||
|
jest.mock('@verdaccio/auth', () => ({
|
||||||
|
Auth: class {
|
||||||
|
apiJWTmiddleware() {
|
||||||
|
return mockApiJWTmiddleware();
|
||||||
|
}
|
||||||
|
allow_access (_d, f_, cb) {
|
||||||
|
cb(null, true)
|
||||||
|
}
|
||||||
|
allow_publish (_d, f_, cb) {
|
||||||
|
cb(null, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_unpublish (_d, f_, cb) {
|
||||||
|
cb(null, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// const mockStorage = jest.fn(() => {
|
||||||
|
// const { Storage } = jest.requireActual('@verdaccio/store');
|
||||||
|
// return {
|
||||||
|
// Storage: class extends Storage {
|
||||||
|
// addPackage(name, metadata, cb) {
|
||||||
|
// super.addPackage(name, metadata, cb);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// jest.mock('@verdaccio/store', () => {
|
||||||
|
// const { Storage } = jest.requireActual('@verdaccio/store');
|
||||||
|
// return ({
|
||||||
|
// Storage: class extends Storage {
|
||||||
|
// addPackage(name, metadata, cb) {
|
||||||
|
// // super.addPackage(name, metadata, cb);
|
||||||
|
// return mockStorage(name, metadata, cb);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
describe('publish', () => {
|
||||||
|
describe('handle invalid publish formats', () => {
|
||||||
|
const pkgName = 'test';
|
||||||
|
const pkgMetadata = generatePackageMetadata(pkgName, '1.0.0');
|
||||||
|
test('should fail on publish a bad _attachments package', async (done) => {
|
||||||
|
const app = await initializeServer('publish.yaml');
|
||||||
|
return supertest(app)
|
||||||
|
.put(`/${encodeURIComponent(pkgName)}`)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.send(JSON.stringify(Object.assign({}, pkgMetadata, {
|
||||||
|
_attachments: {}
|
||||||
|
})))
|
||||||
|
.set('accept', HEADERS.GZIP)
|
||||||
|
.expect(HTTP_STATUS.BAD_REQUEST)
|
||||||
|
.then(response => {
|
||||||
|
console.log("response.body", response.body);
|
||||||
|
expect(response.body.error).toEqual(API_ERROR.UNSUPORTED_REGISTRY_CALL);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should fail on publish a bad versions package', async (done) => {
|
||||||
|
const app = await initializeServer('publish.yaml');
|
||||||
|
return supertest(app)
|
||||||
|
.put(`/${encodeURIComponent(pkgName)}`)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.send(JSON.stringify(Object.assign({}, pkgMetadata, {
|
||||||
|
versions: ''
|
||||||
|
})))
|
||||||
|
.set('accept', HEADERS.GZIP)
|
||||||
|
.expect(HTTP_STATUS.BAD_REQUEST)
|
||||||
|
.then(response => {
|
||||||
|
console.log("response.body", response.body);
|
||||||
|
expect(response.body.error).toEqual(API_ERROR.UNSUPORTED_REGISTRY_CALL);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('publish a package', () => {
|
||||||
|
test('should publish a package', async (done) => {
|
||||||
|
const app = await initializeServer('publish.yaml');
|
||||||
|
return publishVersion(app, 'publish.yaml', 'foo', '1.0.0')
|
||||||
|
.expect(HTTP_STATUS.CREATED)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.body.ok).toEqual(API_MESSAGE.PKG_CREATED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should publish a new package', async (done) => {
|
||||||
|
const pkgName = 'test';
|
||||||
|
const pkgMetadata = generatePackageMetadata(pkgName, '1.0.0');
|
||||||
|
const app = await initializeServer('publish.yaml');
|
||||||
|
return supertest(app)
|
||||||
|
.put(`/${encodeURIComponent(pkgName)}`)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.send(JSON.stringify(Object.assign({}, pkgMetadata, {
|
||||||
|
_attachments: null
|
||||||
|
})))
|
||||||
|
.set('accept', HEADERS.GZIP)
|
||||||
|
.expect(HTTP_STATUS.CREATED)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.body.ok).toEqual(API_MESSAGE.PKG_CREATED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should publish a new package with no readme', async (done) => {
|
||||||
|
const pkgName = 'test';
|
||||||
|
const pkgMetadata = generatePackageMetadata(pkgName, '1.0.0');
|
||||||
|
const app = await initializeServer('publish.yaml');
|
||||||
|
return supertest(app)
|
||||||
|
.put(`/${encodeURIComponent(pkgName)}`)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.send(JSON.stringify(Object.assign({}, pkgMetadata, {
|
||||||
|
versions: {
|
||||||
|
['1.0.0'] : {
|
||||||
|
readme: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
.set('accept', HEADERS.GZIP)
|
||||||
|
.expect(HTTP_STATUS.CREATED)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.body.ok).toEqual(API_MESSAGE.PKG_CREATED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('should fails on publish a duplicated package', async (done) => {
|
||||||
|
const app = await initializeServer('publish.yaml');
|
||||||
|
await publishVersion(app, 'publish.yaml', 'foo', '1.0.0');
|
||||||
|
return publishVersion(app, 'publish.yaml', 'foo', '1.0.0')
|
||||||
|
.expect(HTTP_STATUS.CONFLICT)
|
||||||
|
.then(response => {
|
||||||
|
console.log("response.body", response.body);
|
||||||
|
expect(response.body.error).toEqual(API_ERROR.PACKAGE_EXIST);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unpublish a package', () => {
|
||||||
|
let app;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = await initializeServer('publish.yaml');
|
||||||
|
await publishVersion(app, 'publish.yaml', 'foo', '1.0.0');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should unpublish a package', () => {
|
||||||
|
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('star a package', () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
237
packages/api/test/integration/user.spec.ts
Normal file
237
packages/api/test/integration/user.spec.ts
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
import supertest from 'supertest';
|
||||||
|
|
||||||
|
import { initializeServer } from './_helper';
|
||||||
|
import { HTTP_STATUS, API_ERROR } from '@verdaccio/commons-api';
|
||||||
|
import {HEADERS, HEADER_TYPE, API_MESSAGE} from '@verdaccio/dev-commons';
|
||||||
|
import {$RequestExtend, $ResponseExtend} from "@verdaccio/dev-types";
|
||||||
|
import {getBadRequest, getConflict, getUnauthorized} from "@verdaccio/commons-api/lib";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
const mockApiJWTmiddleware = jest.fn(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: 'test', groups: [], real_groups: []};
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockAuthenticate = jest.fn(() => (_name, _password, callback): void => {
|
||||||
|
return callback(null, ['all']);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockAddUser = jest.fn(() => (_name, _password, callback): void => {
|
||||||
|
return callback(getConflict(API_ERROR.USERNAME_ALREADY_REGISTERED));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
jest.mock('@verdaccio/auth', () => ({
|
||||||
|
getApiToken: () => 'token',
|
||||||
|
Auth: class {
|
||||||
|
apiJWTmiddleware() {
|
||||||
|
return mockApiJWTmiddleware();
|
||||||
|
}
|
||||||
|
allow_access (_d, f_, cb) {
|
||||||
|
cb(null, true);
|
||||||
|
}
|
||||||
|
add_user (name, password, callback) {
|
||||||
|
mockAddUser()(name, password, callback);
|
||||||
|
}
|
||||||
|
authenticate (_name, _password, callback) {
|
||||||
|
mockAuthenticate()(_name, _password, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('user', () => {
|
||||||
|
const credentials = { name: 'test', password: 'test' };
|
||||||
|
|
||||||
|
test('should test add a new user', async (done) => {
|
||||||
|
mockApiJWTmiddleware.mockImplementationOnce(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: undefined};
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
mockAddUser.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||||
|
return callback(null, true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
supertest(await initializeServer('user.yaml'))
|
||||||
|
.put(`/-/user/org.couchdb.user:newUser`)
|
||||||
|
.send({
|
||||||
|
name: 'newUser',
|
||||||
|
password: 'newUser'
|
||||||
|
})
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.CREATED)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
expect(res.body.ok).toBeDefined();
|
||||||
|
expect(res.body.token).toBeDefined();
|
||||||
|
const token = res.body.token;
|
||||||
|
expect(typeof token).toBe('string');
|
||||||
|
expect(res.body.ok).toMatch(`user 'newUser' created`);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should test fails on add a existing user with login', async (done) => {
|
||||||
|
mockApiJWTmiddleware.mockImplementationOnce(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: undefined};
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
supertest(await initializeServer('user.yaml'))
|
||||||
|
.put('/-/user/org.couchdb.user:jotaNew')
|
||||||
|
.send(credentials)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.CONFLICT)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
expect(res.body.error).toBeDefined();
|
||||||
|
expect(res.body.error).toMatch(API_ERROR.USERNAME_ALREADY_REGISTERED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should log in as existing user', async (done) => {
|
||||||
|
supertest(await initializeServer('user.yaml'))
|
||||||
|
.put(`/-/user/org.couchdb.user:${credentials.name}`)
|
||||||
|
.send(credentials)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.CREATED)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.body).toBeTruthy();
|
||||||
|
expect(res.body.ok).toMatch(`you are authenticated as \'${credentials.name}\'`);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should test fails add a new user with missing name', async (done) => {
|
||||||
|
mockApiJWTmiddleware.mockImplementationOnce(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: undefined };
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
mockAddUser.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||||
|
return callback(getBadRequest(API_ERROR.USERNAME_PASSWORD_REQUIRED));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const credentialsShort = _.cloneDeep(credentials);
|
||||||
|
delete credentialsShort.name;
|
||||||
|
|
||||||
|
supertest(await initializeServer('user.yaml'))
|
||||||
|
.put(`/-/user/org.couchdb.user:${credentials.name}`)
|
||||||
|
.send(credentialsShort)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.BAD_REQUEST)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.body.error).toBeDefined();
|
||||||
|
expect(res.body.error).toMatch(API_ERROR.USERNAME_PASSWORD_REQUIRED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should test fails add a new user with missing password', async (done) => {
|
||||||
|
mockApiJWTmiddleware.mockImplementationOnce(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: undefined};
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const credentialsShort = _.cloneDeep(credentials);
|
||||||
|
delete credentialsShort.password;
|
||||||
|
|
||||||
|
supertest(await initializeServer('user.yaml'))
|
||||||
|
.put(`/-/user/org.couchdb.user:${credentials.name}`)
|
||||||
|
.send(credentialsShort)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.BAD_REQUEST)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.body.error).toBeDefined();
|
||||||
|
// FIXME: message is not 100% accurate
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
expect(res.body.error).toMatch(API_ERROR.PASSWORD_SHORT());
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should test fails add a new user with wrong password', async (done) => {
|
||||||
|
mockApiJWTmiddleware.mockImplementationOnce(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: 'test'};
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||||
|
return callback(getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const credentialsShort = _.cloneDeep(credentials);
|
||||||
|
credentialsShort.password = 'failPassword';
|
||||||
|
|
||||||
|
supertest(await initializeServer('user.yaml'))
|
||||||
|
.put('/-/user/org.couchdb.user:test')
|
||||||
|
.send(credentialsShort)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.UNAUTHORIZED)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.body.error).toBeDefined();
|
||||||
|
expect(res.body.error).toMatch(API_ERROR.BAD_USERNAME_PASSWORD);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should be able to logout an user', async (done) => {
|
||||||
|
mockApiJWTmiddleware.mockImplementationOnce(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: 'test'};
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
|
||||||
|
return callback(getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const credentialsShort = _.cloneDeep(credentials);
|
||||||
|
credentialsShort.password = 'failPassword';
|
||||||
|
|
||||||
|
supertest(await initializeServer('user.yaml'))
|
||||||
|
.delete('/-/user/token/someSecretToken')
|
||||||
|
.send(credentialsShort)
|
||||||
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.OK)
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(res.body.ok).toMatch(API_MESSAGE.LOGGED_OUT);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
53
packages/api/test/integration/whoami.spec.ts
Normal file
53
packages/api/test/integration/whoami.spec.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import supertest from 'supertest';
|
||||||
|
|
||||||
|
import {initializeServer } from './_helper';
|
||||||
|
import { HTTP_STATUS } from '@verdaccio/commons-api';
|
||||||
|
import { HEADERS} from '@verdaccio/dev-commons';
|
||||||
|
import {$RequestExtend, $ResponseExtend} from "@verdaccio/dev-types";
|
||||||
|
|
||||||
|
const mockApiJWTmiddleware = jest.fn(() =>
|
||||||
|
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
||||||
|
req.remote_user = { name: 'foo', groups: [], real_groups: []}
|
||||||
|
_next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
jest.mock('@verdaccio/auth', () => ({
|
||||||
|
Auth: class {
|
||||||
|
apiJWTmiddleware() {
|
||||||
|
return mockApiJWTmiddleware();
|
||||||
|
}
|
||||||
|
allow_access (_d, f_, cb) {
|
||||||
|
cb(null, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('whoami', () => {
|
||||||
|
test.skip('should test referer /whoami endpoint', async (done) => {
|
||||||
|
return supertest(await initializeServer('whoami.yaml'))
|
||||||
|
.get('/whoami')
|
||||||
|
.set('referer', 'whoami')
|
||||||
|
.expect(HTTP_STATUS.OK)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.skip('should test no referer /whoami endpoint', async (done) => {
|
||||||
|
return supertest(await initializeServer('whoami.yaml'))
|
||||||
|
.get('/whoami')
|
||||||
|
.expect(HTTP_STATUS.NOT_FOUND)
|
||||||
|
.end(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('should return the logged username', async () => {
|
||||||
|
return supertest(await initializeServer('whoami.yaml'))
|
||||||
|
.get('/-/whoami')
|
||||||
|
.set('Accept', HEADERS.JSON)
|
||||||
|
.expect('Content-Type', HEADERS.JSON_CHARSET)
|
||||||
|
.expect(HTTP_STATUS.OK)
|
||||||
|
.then(response => {
|
||||||
|
expect(response.body.username).toEqual('foo');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
import { addVersion, uploadPackageTarball, removeTarball, unPublishPackage, publishPackage } from '../src/publish';
|
import { addVersion, uploadPackageTarball, removeTarball, unPublishPackage, publishPackage } from '../../src/publish';
|
||||||
import { HTTP_STATUS, API_ERROR } from '@verdaccio/dev-commons';
|
import { HTTP_STATUS, API_ERROR } from '@verdaccio/dev-commons';
|
||||||
|
|
||||||
const REVISION_MOCK = '15-e53a77096b0ee33e';
|
const REVISION_MOCK = '15-e53a77096b0ee33e';
|
||||||
@ -82,7 +82,7 @@ describe('Publish endpoints - upload package tarball', () => {
|
|||||||
pipe: jest.fn(),
|
pipe: jest.fn(),
|
||||||
on: jest.fn(),
|
on: jest.fn(),
|
||||||
};
|
};
|
||||||
res = { status: jest.fn(), report_error: jest.fn() };
|
res = { status: jest.fn(), locals: { report_error: jest.fn() }};
|
||||||
next = jest.fn();
|
next = jest.fn();
|
||||||
});
|
});
|
||||||
|
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable curly */
|
||||||
// ensure that all arguments are validated
|
// ensure that all arguments are validated
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
@ -13,7 +14,7 @@ import fs from 'fs';
|
|||||||
*/
|
*/
|
||||||
describe('api endpoint app.param()', () => {
|
describe('api endpoint app.param()', () => {
|
||||||
let m;
|
let m;
|
||||||
const requirePath = path.normalize(path.join(__dirname, '../src/index.ts'));
|
const requirePath = path.normalize(path.join(__dirname, '../../src/index.ts'));
|
||||||
const source = fs.readFileSync(requirePath, 'utf8');
|
const source = fs.readFileSync(requirePath, 'utf8');
|
||||||
const very_scary_regexp = /\n\s*app\.(\w+)\s*\(\s*(("[^"]*")|('[^']*'))\s*,/g;
|
const very_scary_regexp = /\n\s*app\.(\w+)\s*\(\s*(("[^"]*")|('[^']*'))\s*,/g;
|
||||||
const appParams = {};
|
const appParams = {};
|
@ -23,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/commons-api": "9.4.0",
|
"@verdaccio/commons-api": "9.6.1",
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"@verdaccio/loaders": "5.0.0-alpha.0",
|
"@verdaccio/loaders": "5.0.0-alpha.0",
|
||||||
"@verdaccio/logger": "5.0.0-alpha.0",
|
"@verdaccio/logger": "5.0.0-alpha.0",
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
"@verdaccio/config": "5.0.0-alpha.0",
|
"@verdaccio/config": "5.0.0-alpha.0",
|
||||||
"@verdaccio/node-api": "5.0.0-alpha.0",
|
"@verdaccio/node-api": "5.0.0-alpha.0",
|
||||||
"@verdaccio/utils": "5.0.0-alpha.0",
|
"@verdaccio/utils": "5.0.0-alpha.0",
|
||||||
"commander": "3.0.2",
|
"commander": "5.1.0",
|
||||||
"envinfo": "7.4.0",
|
"envinfo": "7.4.0",
|
||||||
"kleur": "3.0.3",
|
"kleur": "3.0.3",
|
||||||
"semver": "7.3.2"
|
"semver": "7.3.2"
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import { Package } from "@verdaccio/types";
|
import { Package } from "@verdaccio/types";
|
||||||
|
|
||||||
export function generatePackageMetadata(pkgName: string, version = '1.0.0'): Package {
|
export interface DistTags {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generatePackageMetadata(pkgName: string, version = '1.0.0', distTags: DistTags = {['latest']: version}): Package {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return {
|
return {
|
||||||
"_id": pkgName,
|
"_id": pkgName,
|
||||||
"name": pkgName,
|
"name": pkgName,
|
||||||
"dist-tags": {
|
"dist-tags": {
|
||||||
"latest": version
|
...distTags
|
||||||
},
|
},
|
||||||
"versions": {
|
"versions": {
|
||||||
[version]: {
|
[version]: {
|
||||||
|
@ -15,14 +15,14 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://verdaccio.org",
|
"homepage": "https://verdaccio.org",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/commons-api": "9.4.0",
|
"@verdaccio/commons-api": "9.6.1",
|
||||||
"@verdaccio/logger": "5.0.0-alpha.0",
|
"@verdaccio/logger": "5.0.0-alpha.0",
|
||||||
"handlebars": "4.5.3",
|
"handlebars": "4.5.3",
|
||||||
"request": "2.87.0"
|
"request": "2.87.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"@verdaccio/types": "9.3.0"
|
"@verdaccio/types": "9.5.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf ./build",
|
"clean": "rimraf ./build",
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"build": "npm run build:js && npm run build:types"
|
"build": "npm run build:js && npm run build:types"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/commons-api": "9.4.0",
|
"@verdaccio/commons-api": "9.6.1",
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"dayjs": "1.8.19",
|
"dayjs": "1.8.19",
|
||||||
"fast-safe-stringify": "2.0.7",
|
"fast-safe-stringify": "2.0.7",
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/pino": "6.0.1",
|
"@types/pino": "6.0.1",
|
||||||
"@verdaccio/types": "9.3.0"
|
"@verdaccio/types": "9.5.0"
|
||||||
},
|
},
|
||||||
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
"build": "npm run build:js && npm run build:types"
|
"build": "npm run build:js && npm run build:types"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/commons-api": "9.4.0",
|
"@verdaccio/commons-api": "9.6.1",
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"@verdaccio/logger": "5.0.0-alpha.0",
|
"@verdaccio/logger": "5.0.0-alpha.0",
|
||||||
"@verdaccio/utils": "5.0.0-alpha.0",
|
"@verdaccio/utils": "5.0.0-alpha.0",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -13,6 +14,7 @@ import { $ResponseExtend, $RequestExtend, $NextFunctionVer, IAuth } from '@verda
|
|||||||
import { Config, Package, RemoteUser } from '@verdaccio/types';
|
import { Config, Package, RemoteUser } from '@verdaccio/types';
|
||||||
import { logger } from '@verdaccio/logger';
|
import { logger } from '@verdaccio/logger';
|
||||||
import { VerdaccioError } from '@verdaccio/commons-api';
|
import { VerdaccioError } from '@verdaccio/commons-api';
|
||||||
|
import {HttpError} from "http-errors";
|
||||||
|
|
||||||
export function match(regexp: RegExp): any {
|
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 {
|
||||||
@ -110,8 +112,7 @@ export function allow(auth: IAuth): Function {
|
|||||||
const packageName = req.params.scope ? `@${req.params.scope}/${req.params.package}` : req.params.package;
|
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 packageVersion = req.params.filename ? getVersionFromTarball(req.params.filename) : undefined;
|
||||||
const remote: RemoteUser = req.remote_user;
|
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 {
|
auth['allow_' + action]({ packageName, packageVersion }, remote, function(error, allowed): void {
|
||||||
req.resume();
|
req.resume();
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -148,7 +149,8 @@ export function final(body: FinalBody, req: $RequestExtend, res: $ResponseExtend
|
|||||||
|
|
||||||
if (typeof body === 'object' && _.isNil(body) === false) {
|
if (typeof body === 'object' && _.isNil(body) === false) {
|
||||||
if (typeof (body as MiddlewareError).error === 'string') {
|
if (typeof (body as MiddlewareError).error === 'string') {
|
||||||
res._verdaccio_error = (body as MiddlewareError).error;
|
res.locals._verdaccio_error = (body as MiddlewareError).error;
|
||||||
|
// res._verdaccio_error = (body as MiddlewareError).error;
|
||||||
}
|
}
|
||||||
body = JSON.stringify(body, undefined, ' ') + '\n';
|
body = JSON.stringify(body, undefined, ' ') + '\n';
|
||||||
}
|
}
|
||||||
@ -181,8 +183,7 @@ export const LOG_STATUS_MESSAGE = "@{status}, user: @{user}(@{remoteIP}), req: '
|
|||||||
export const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`;
|
export const LOG_VERDACCIO_ERROR = `${LOG_STATUS_MESSAGE}, error: @{!error}`;
|
||||||
export const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`;
|
export const LOG_VERDACCIO_BYTES = `${LOG_STATUS_MESSAGE}, bytes: @{bytes.in}/@{bytes.out}`;
|
||||||
|
|
||||||
export function log(config: Config) {
|
export function log(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
||||||
return function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
|
||||||
// logger
|
// logger
|
||||||
req.log = logger.child({ sub: 'in' });
|
req.log = logger.child({ sub: 'in' });
|
||||||
|
|
||||||
@ -197,10 +198,7 @@ export function log(config: Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.url = req.originalUrl;
|
req.url = req.originalUrl;
|
||||||
// avoid log noise data from static content
|
req.log.info({ req: req, ip: req.ip }, "@{ip} requested '@{req.method} @{req.url}'");
|
||||||
if (req.originalUrl.match(/static/) === null) {
|
|
||||||
req.log.info({req: req, ip: req.ip}, "@{ip} requested '@{req.method} @{req.url}'");
|
|
||||||
}
|
|
||||||
req.originalUrl = req.url;
|
req.originalUrl = req.url;
|
||||||
|
|
||||||
if (_.isNil(_auth) === false) {
|
if (_.isNil(_auth) === false) {
|
||||||
@ -212,11 +210,9 @@ export function log(config: Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let bytesin = 0;
|
let bytesin = 0;
|
||||||
if (config?.experiments?.bytesin_off !== true) {
|
|
||||||
req.on('data', function(chunk): void {
|
req.on('data', function(chunk): void {
|
||||||
bytesin += chunk.length;
|
bytesin += chunk.length;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let bytesout = 0;
|
let bytesout = 0;
|
||||||
const _write = res.write;
|
const _write = res.write;
|
||||||
@ -229,26 +225,18 @@ export function log(config: Config) {
|
|||||||
_write.apply(res, arguments);
|
_write.apply(res, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
let logHasBeenCalled = false;
|
|
||||||
const log = function(): void {
|
const log = function(): void {
|
||||||
if (logHasBeenCalled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logHasBeenCalled = true;
|
|
||||||
|
|
||||||
const forwardedFor = req.headers['x-forwarded-for'];
|
const forwardedFor = req.headers['x-forwarded-for'];
|
||||||
const remoteAddress = req.connection.remoteAddress;
|
const remoteAddress = req.connection.remoteAddress;
|
||||||
const remoteIP = forwardedFor ? `${forwardedFor} via ${remoteAddress}` : remoteAddress;
|
const remoteIP = forwardedFor ? `${forwardedFor} via ${remoteAddress}` : remoteAddress;
|
||||||
let message;
|
let message;
|
||||||
if (res._verdaccio_error) {
|
if (res.locals._verdaccio_error) {
|
||||||
message = LOG_VERDACCIO_ERROR;
|
message = LOG_VERDACCIO_ERROR;
|
||||||
} else {
|
} else {
|
||||||
message = LOG_VERDACCIO_BYTES;
|
message = LOG_VERDACCIO_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
req.url = req.originalUrl;
|
req.url = req.originalUrl;
|
||||||
// avoid log noise data from static content
|
|
||||||
if (req.url.match(/static/) === null) {
|
|
||||||
req.log.warn(
|
req.log.warn(
|
||||||
{
|
{
|
||||||
request: {
|
request: {
|
||||||
@ -259,7 +247,7 @@ export function log(config: Config) {
|
|||||||
user: (req.remote_user && req.remote_user.name) || null,
|
user: (req.remote_user && req.remote_user.name) || null,
|
||||||
remoteIP,
|
remoteIP,
|
||||||
status: res.statusCode,
|
status: res.statusCode,
|
||||||
error: res._verdaccio_error,
|
error: res.locals._verdaccio_error,
|
||||||
bytes: {
|
bytes: {
|
||||||
in: bytesin,
|
in: bytesin,
|
||||||
out: bytesout,
|
out: bytesout,
|
||||||
@ -268,8 +256,7 @@ export function log(config: Config) {
|
|||||||
message
|
message
|
||||||
);
|
);
|
||||||
req.originalUrl = req.url;
|
req.originalUrl = req.url;
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
req.on('close', function(): void {
|
req.on('close', function(): void {
|
||||||
log();
|
log();
|
||||||
@ -286,16 +273,32 @@ export function log(config: Config) {
|
|||||||
log();
|
log();
|
||||||
};
|
};
|
||||||
next();
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleError(err: HttpError, req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {
|
||||||
|
if (_.isError(err)) {
|
||||||
|
if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
if (_.isFunction(res.locals.report_error) === false) {
|
||||||
|
// in case of very early error this middleware may not be loaded before error is generated
|
||||||
|
// fixing that
|
||||||
|
errorReportingMiddleware(req, res, _.noop);
|
||||||
|
}
|
||||||
|
res.locals.report_error(err);
|
||||||
|
} else {
|
||||||
|
// Fall to Middleware.final
|
||||||
|
return next(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Middleware
|
// 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.locals.report_error =
|
||||||
res.report_error ||
|
res.locals.report_error ||
|
||||||
function(err: VerdaccioError): void {
|
function(err: VerdaccioError): void {
|
||||||
if (err.status && err.status >= HTTP_STATUS.BAD_REQUEST && err.status < 600) {
|
if (err.status && err.status >= HTTP_STATUS.BAD_REQUEST && err.status < 600) {
|
||||||
if (!res.headersSent) {
|
if (_.isNil(res.headersSent) === false) {
|
||||||
res.status(err.status);
|
res.status(err.status);
|
||||||
next({ error: err.message || API_ERROR.UNKNOWN_ERROR });
|
next({ error: err.message || API_ERROR.UNKNOWN_ERROR });
|
||||||
}
|
}
|
||||||
|
14
packages/middleware/types/custom.d.ts
vendored
14
packages/middleware/types/custom.d.ts
vendored
@ -1,4 +1,7 @@
|
|||||||
|
// <reference types="node" />
|
||||||
|
|
||||||
import { Logger, RemoteUser } from "@verdaccio/types";
|
import { Logger, RemoteUser } from "@verdaccio/types";
|
||||||
|
import * as http from "http";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace Express {
|
namespace Express {
|
||||||
@ -7,10 +10,11 @@ declare global {
|
|||||||
log: Logger;
|
log: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Response {
|
// FIXME:
|
||||||
report_error: any;
|
// export interface Response extends http.ServerResponse, Express.Response {
|
||||||
_verdaccio_error: any;
|
// report_error: any;
|
||||||
socket?: any;
|
// _verdaccio_error: any;
|
||||||
}
|
// socket?: any;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,16 +24,16 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"@verdaccio/local-storage": "9.5.0",
|
"@verdaccio/local-storage": "9.6.1",
|
||||||
"@verdaccio/logger": "5.0.0-alpha.0",
|
"@verdaccio/logger": "5.0.0-alpha.0",
|
||||||
"@verdaccio/streams": "9.5.0",
|
"@verdaccio/streams": "9.6.1",
|
||||||
"@verdaccio/utils": "5.0.0-alpha.0",
|
"@verdaccio/utils": "5.0.0-alpha.0",
|
||||||
"JSONStream": "1.3.5",
|
"JSONStream": "1.3.5",
|
||||||
"request": "2.87.0"
|
"request": "2.87.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@verdaccio/dev-types": "5.0.0-alpha.0",
|
"@verdaccio/dev-types": "5.0.0-alpha.0",
|
||||||
"@verdaccio/types": "9.3.0"
|
"@verdaccio/types": "9.5.0"
|
||||||
},
|
},
|
||||||
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
||||||
}
|
}
|
||||||
|
@ -85,12 +85,12 @@ const defineAPI = function(config: IConfig, storage: IStorageHandler): any {
|
|||||||
if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {
|
if (err.code === 'ECONNABORT' && res.statusCode === HTTP_STATUS.NOT_MODIFIED) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
if (_.isFunction(res.report_error) === false) {
|
if (_.isFunction(res.locals.report_error) === false) {
|
||||||
// in case of very early error this middleware may not be loaded before error is generated
|
// in case of very early error this middleware may not be loaded before error is generated
|
||||||
// fixing that
|
// fixing that
|
||||||
errorReportingMiddleware(req, res, _.noop);
|
errorReportingMiddleware(req, res, _.noop);
|
||||||
}
|
}
|
||||||
res.report_error(err);
|
res.locals.report_error(err);
|
||||||
} else {
|
} else {
|
||||||
// Fall to Middleware.final
|
// Fall to Middleware.final
|
||||||
return next(err);
|
return next(err);
|
||||||
|
8
packages/server/test/.eslintrc
Normal file
8
packages/server/test/.eslintrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/explicit-function-return-type": 0,
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": 0,
|
||||||
|
"@typescript-eslint/no-unused-vars": 2,
|
||||||
|
"no-console": 0
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ import path from 'path';
|
|||||||
import endPointAPI from '@verdaccio/server';
|
import endPointAPI from '@verdaccio/server';
|
||||||
import {
|
import {
|
||||||
HEADERS,
|
HEADERS,
|
||||||
API_ERROR,
|
|
||||||
HTTP_STATUS,
|
HTTP_STATUS,
|
||||||
HEADER_TYPE,
|
HEADER_TYPE,
|
||||||
API_MESSAGE,
|
API_MESSAGE,
|
||||||
@ -85,67 +84,7 @@ describe('endpoint unit test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Registry API Endpoints', () => {
|
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) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should test no referer /whoami endpoint', (done) => {
|
|
||||||
request(app)
|
|
||||||
.get('/whoami')
|
|
||||||
.expect(HTTP_STATUS.NOT_FOUND)
|
|
||||||
.end(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should test /-/whoami endpoint', (done) => {
|
|
||||||
request(app)
|
|
||||||
.get('/-/whoami')
|
|
||||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
||||||
.expect(HTTP_STATUS.OK)
|
|
||||||
.end(function(err) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should test /whoami endpoint', (done) => {
|
|
||||||
request(app)
|
|
||||||
.get('/-/whoami')
|
|
||||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
||||||
.expect(HTTP_STATUS.OK)
|
|
||||||
.end(function(err) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('should test user api', () => {
|
describe('should test user api', () => {
|
||||||
|
|
||||||
describe('should test authorization headers with tokens only errors', () => {
|
describe('should test authorization headers with tokens only errors', () => {
|
||||||
test('should fails on protected endpoint /-/auth-package bad format', (done) => {
|
test('should fails on protected endpoint /-/auth-package bad format', (done) => {
|
||||||
request(app)
|
request(app)
|
||||||
@ -219,106 +158,6 @@ describe('endpoint unit test', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should test fails add a new user with missing name', (done) => {
|
|
||||||
|
|
||||||
const credentialsShort = _.cloneDeep(credentials);
|
|
||||||
delete credentialsShort.name;
|
|
||||||
|
|
||||||
request(app)
|
|
||||||
.put(`/-/user/org.couchdb.user:${credentials.name}`)
|
|
||||||
.send(credentialsShort)
|
|
||||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
||||||
.expect(HTTP_STATUS.BAD_REQUEST)
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(res.body.error).toBeDefined();
|
|
||||||
expect(res.body.error).toMatch(API_ERROR.USERNAME_PASSWORD_REQUIRED);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should test fails add a new user with missing password', (done) => {
|
|
||||||
|
|
||||||
const credentialsShort = _.cloneDeep(credentials);
|
|
||||||
delete credentialsShort.password;
|
|
||||||
|
|
||||||
request(app)
|
|
||||||
.put(`/-/user/org.couchdb.user:${credentials.name}`)
|
|
||||||
.send(credentialsShort)
|
|
||||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
||||||
.expect(HTTP_STATUS.BAD_REQUEST)
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(res.body.error).toBeDefined();
|
|
||||||
// FIXME: message is not 100% accurate
|
|
||||||
/* eslint new-cap: 0 */
|
|
||||||
expect(res.body.error).toMatch(API_ERROR.PASSWORD_SHORT());
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should test add a new user with login', (done) => {
|
|
||||||
const newCredentials = _.cloneDeep(credentials);
|
|
||||||
newCredentials.name = 'jotaNew';
|
|
||||||
|
|
||||||
request(app)
|
|
||||||
.put('/-/user/org.couchdb.user:jotaNew')
|
|
||||||
.send(newCredentials)
|
|
||||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
||||||
.expect(HTTP_STATUS.CREATED)
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
expect(res.body).toBeTruthy();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should test fails on add a existing user with login', (done) => {
|
|
||||||
request(app)
|
|
||||||
.put('/-/user/org.couchdb.user:jotaNew')
|
|
||||||
.send(credentials)
|
|
||||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
||||||
.expect(HTTP_STATUS.CONFLICT)
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
expect(res.body.error).toBeDefined();
|
|
||||||
expect(res.body.error).toMatch(API_ERROR.USERNAME_ALREADY_REGISTERED);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should test fails add a new user with wrong password', (done) => {
|
|
||||||
|
|
||||||
const credentialsShort = _.cloneDeep(credentials);
|
|
||||||
credentialsShort.password = 'failPassword';
|
|
||||||
|
|
||||||
request(app)
|
|
||||||
.put('/-/user/org.couchdb.user:jota')
|
|
||||||
.send(credentialsShort)
|
|
||||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
||||||
.expect(HTTP_STATUS.UNAUTHORIZED)
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(res.body.error).toBeDefined();
|
|
||||||
expect(res.body.error).toMatch(/unauthorized/);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should test package api', () => {
|
describe('should test package api', () => {
|
||||||
|
6
packages/server/types/custom.d.ts
vendored
6
packages/server/types/custom.d.ts
vendored
@ -6,11 +6,5 @@ declare global {
|
|||||||
remote_user: RemoteUser;
|
remote_user: RemoteUser;
|
||||||
log: Logger;
|
log: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Response {
|
|
||||||
report_error: any;
|
|
||||||
_verdaccio_error: any;
|
|
||||||
socket?: any;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,20 +23,20 @@
|
|||||||
"build": "npm run build:js && npm run build:types"
|
"build": "npm run build:js && npm run build:types"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/commons-api": "9.4.0",
|
"@verdaccio/commons-api": "9.6.1",
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"@verdaccio/loaders": "5.0.0-alpha.0",
|
"@verdaccio/loaders": "5.0.0-alpha.0",
|
||||||
"@verdaccio/local-storage": "9.5.0",
|
"@verdaccio/local-storage": "9.6.1",
|
||||||
"@verdaccio/logger": "5.0.0-alpha.0",
|
"@verdaccio/logger": "5.0.0-alpha.0",
|
||||||
"@verdaccio/proxy": "5.0.0-alpha.0",
|
"@verdaccio/proxy": "5.0.0-alpha.0",
|
||||||
"@verdaccio/streams": "9.5.0",
|
"@verdaccio/streams": "9.6.1",
|
||||||
"@verdaccio/utils": "5.0.0-alpha.0",
|
"@verdaccio/utils": "5.0.0-alpha.0",
|
||||||
"async": "3.1.1",
|
"async": "3.1.1",
|
||||||
"lodash": "4.17.15",
|
"lodash": "4.17.15",
|
||||||
"semver": "7.1.2"
|
"semver": "7.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@verdaccio/types": "9.3.0"
|
"@verdaccio/types": "9.5.0"
|
||||||
},
|
},
|
||||||
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
"gitHead": "7c246ede52ff717707fcae66dd63fc4abd536982"
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
"homepage": "https://verdaccio.org",
|
"homepage": "https://verdaccio.org",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
"@verdaccio/dev-commons": "5.0.0-alpha.0",
|
||||||
"@verdaccio/readme": "9.5.0",
|
"@verdaccio/readme": "9.6.1",
|
||||||
"js-yaml": "3.13.1",
|
"js-yaml": "3.13.1",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
"minimatch": "3.0.4",
|
"minimatch": "3.0.4",
|
||||||
|
8
packages/utils/test/.eslintrc
Normal file
8
packages/utils/test/.eslintrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/explicit-function-return-type": 0,
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": 0,
|
||||||
|
"no-console": 0,
|
||||||
|
"@typescript-eslint/no-unused-vars": 1
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@verdaccio/dev-types": "5.0.0-alpha.0",
|
"@verdaccio/dev-types": "5.0.0-alpha.0",
|
||||||
"@verdaccio/types": "9.3.0"
|
"@verdaccio/types": "9.5.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf ./build",
|
"clean": "rimraf ./build",
|
||||||
|
6
packages/web/types/custom.d.ts
vendored
6
packages/web/types/custom.d.ts
vendored
@ -6,11 +6,5 @@ declare global {
|
|||||||
remote_user: RemoteUser;
|
remote_user: RemoteUser;
|
||||||
log: Logger;
|
log: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Response {
|
|
||||||
report_error: any;
|
|
||||||
_verdaccio_error: any;
|
|
||||||
socket?: any;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"incremental": true,
|
"incremental": false,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
BIN
yarn.lock
BIN
yarn.lock
Binary file not shown.
Loading…
Reference in New Issue
Block a user