mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-02-17 03:19:36 +01:00
chore: refactor server express tests (#3306)
This commit is contained in:
parent
f42db638eb
commit
353c9f386f
@ -16,7 +16,6 @@
|
||||
"@verdaccio/logger": "6.0.0-alpha.0",
|
||||
"@verdaccio/logger-prettify": "6.0.0-alpha.0",
|
||||
"@verdaccio/middleware": "6.0.0-alpha.0",
|
||||
"@verdaccio/mock": "6.0.0-alpha.0",
|
||||
"@verdaccio/node-api": "6.0.0-alpha.0",
|
||||
"@verdaccio/proxy": "6.0.0-alpha.0",
|
||||
"@verdaccio/server": "6.0.0-alpha.0",
|
||||
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
name: setup verdaccio
|
||||
services:
|
||||
verdaccio:
|
||||
image: verdaccio/verdaccio:5
|
||||
image: verdaccio/verdaccio:nightly-master
|
||||
ports:
|
||||
- 4873:4873
|
||||
steps:
|
||||
|
@ -4,7 +4,7 @@ module.exports = Object.assign({}, config, {
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
// FIXME: increase to 90
|
||||
lines: 43,
|
||||
lines: 42,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -51,7 +51,6 @@
|
||||
"verdaccio-htpasswd": "workspace:11.0.0-6-next.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.15",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.12"
|
||||
},
|
||||
"funding": {
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
createRemoteUser,
|
||||
parseConfigFile,
|
||||
} from '@verdaccio/config';
|
||||
import { getDefaultConfig } from '@verdaccio/config';
|
||||
import {
|
||||
API_ERROR,
|
||||
CHARACTER_ENCODING,
|
||||
@ -16,14 +17,9 @@ import {
|
||||
errorUtils,
|
||||
} from '@verdaccio/core';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import { configExample } from '@verdaccio/mock';
|
||||
import { Config, RemoteUser, Security } from '@verdaccio/types';
|
||||
import {
|
||||
AllowActionCallbackResponse,
|
||||
buildToken,
|
||||
buildUserBuffer,
|
||||
getAuthenticatedMessage,
|
||||
} from '@verdaccio/utils';
|
||||
import { buildToken, buildUserBuffer, getAuthenticatedMessage } from '@verdaccio/utils';
|
||||
import type { AllowActionCallbackResponse } from '@verdaccio/utils';
|
||||
|
||||
import {
|
||||
ActionsAllowed,
|
||||
@ -58,7 +54,7 @@ describe('Auth utilities', () => {
|
||||
function getConfig(configFileName: string, secret: string) {
|
||||
const conf = parseConfigFile(parseConfigurationSecurityFile(configFileName));
|
||||
// @ts-ignore
|
||||
const secConf = _.merge(configExample(), conf);
|
||||
const secConf = _.merge(getDefaultConfig(), conf);
|
||||
secConf.secret = secret;
|
||||
const config: Config = new AppConfig(secConf);
|
||||
|
||||
|
@ -51,7 +51,7 @@ describe('AuthTest', () => {
|
||||
});
|
||||
|
||||
test('should be a fail on login', () => {
|
||||
const config: Config = new AppConfig(_.cloneDeep(authPluginFailureConf));
|
||||
const config: Config = new AppConfig(authPluginFailureConf);
|
||||
config.checkSecretKey('12345');
|
||||
const auth: IAuth = new Auth(config);
|
||||
|
||||
|
@ -1,21 +1,24 @@
|
||||
import path from 'path';
|
||||
|
||||
import { configExample as config } from '@verdaccio/mock';
|
||||
import { getDefaultConfig } from '@verdaccio/config';
|
||||
|
||||
export const authProfileConf = config({
|
||||
export const authProfileConf = {
|
||||
...getDefaultConfig(),
|
||||
auth: {
|
||||
[`${path.join(__dirname, '../partials/plugin/authenticate.success')}`]: {},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const authPluginFailureConf = config({
|
||||
export const authPluginFailureConf = {
|
||||
...getDefaultConfig(),
|
||||
auth: {
|
||||
[`${path.join(__dirname, '../partials/plugin/authenticate.fail')}`]: {},
|
||||
[`${path.join(__dirname, '../partials/plugin/authenticate.fail.js')}`]: {},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const authPluginPassThrougConf = config({
|
||||
export const authPluginPassThrougConf = {
|
||||
...getDefaultConfig(),
|
||||
auth: {
|
||||
[`${path.join(__dirname, '../partials/plugin/authenticate.passthroug')}`]: {},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { getInternalError } from '@verdaccio/commons-api';
|
||||
import { errorUtils } from '@verdaccio/core';
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
authenticate(user, pass, callback) {
|
||||
// we return an 500 error, the second argument must be false.
|
||||
// https://verdaccio.org/docs/en/dev-plugins#onerror
|
||||
callback(getInternalError(), false);
|
||||
callback(errorUtils.getInternalError(), false);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -1,11 +1,5 @@
|
||||
import assert from 'assert';
|
||||
import _ from 'lodash';
|
||||
|
||||
const pkgVersion = require('../package.json').version;
|
||||
const pkgName = require('../package.json').name;
|
||||
|
||||
export function getUserAgent(): string {
|
||||
assert(_.isString(pkgName));
|
||||
assert(_.isString(pkgVersion));
|
||||
return `${pkgName}/${pkgVersion}`;
|
||||
return `verdaccio/${pkgVersion}`;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@
|
||||
"devDependencies": {
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.5",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.14",
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.15",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.12"
|
||||
},
|
||||
"homepage": "https://verdaccio.org",
|
||||
|
@ -50,7 +50,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "16.11.47",
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.15",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.12",
|
||||
"jest-mock-process": "1.5.1",
|
||||
"selfsigned": "1.10.14",
|
||||
|
@ -1,5 +1,10 @@
|
||||
const config = require('../../jest/config');
|
||||
const config = require('../../../jest/config');
|
||||
|
||||
module.exports = Object.assign({}, config, {
|
||||
setupFilesAfterEnv: ['./jest.setup.js'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
// FIXME: increase to 90
|
||||
lines: 85,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1 +0,0 @@
|
||||
jest.setTimeout(20000);
|
@ -50,14 +50,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "16.11.47",
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.15",
|
||||
"@verdaccio/proxy": "workspace:6.0.0-6-next.20",
|
||||
"@verdaccio/test-helper": "workspace:1.1.0-6-next.1",
|
||||
"http-errors": "1.8.1"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
"test": "echo 0",
|
||||
"test": "jest",
|
||||
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
||||
"watch": "pnpm build:js -- --watch",
|
||||
|
@ -14,7 +14,7 @@ export default (app: Application, configPath?: string): void => {
|
||||
next({
|
||||
pid: process.pid,
|
||||
// @ts-ignore
|
||||
main: process.mainModule.filename,
|
||||
main: process.main,
|
||||
conf: configPath,
|
||||
mem: process.memoryUsage(),
|
||||
gc: global.gc,
|
||||
|
@ -21,6 +21,7 @@ import webMiddleware from '@verdaccio/web';
|
||||
|
||||
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';
|
||||
import hookDebug from './debug';
|
||||
import { getUserAgent } from './utils';
|
||||
|
||||
export interface IPluginMiddleware<T> extends IPlugin<T> {
|
||||
register_middlewares(app: any, auth: IBasicAuth<T>, storage: Storage): void;
|
||||
@ -42,7 +43,7 @@ const defineAPI = function (config: IConfig, storage: Storage): any {
|
||||
app.use(log);
|
||||
app.use(errorReportingMiddleware);
|
||||
app.use(function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer): void {
|
||||
res.setHeader('X-Powered-By', config.user_agent);
|
||||
res.setHeader('x-powered-by', getUserAgent(config.user_agent));
|
||||
next();
|
||||
});
|
||||
|
||||
|
11
packages/server/express/src/utils.ts
Normal file
11
packages/server/express/src/utils.ts
Normal file
@ -0,0 +1,11 @@
|
||||
const pkgVersion = require('../package.json').version;
|
||||
|
||||
export function getUserAgent(userAgent: string): string {
|
||||
if (typeof userAgent === 'string') {
|
||||
return userAgent;
|
||||
} else if (userAgent === false) {
|
||||
return 'hidden';
|
||||
}
|
||||
|
||||
return `verdaccio/${pkgVersion}`;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": 0,
|
||||
"@typescript-eslint/explicit-member-accessibility": 0,
|
||||
"@typescript-eslint/no-unused-vars": 2,
|
||||
"no-console": 0
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
## Testing
|
||||
|
||||
The test are structured by feature following this shape:
|
||||
|
||||
```bash
|
||||
test
|
||||
--- feat
|
||||
--- config.yaml
|
||||
--- spec.test.ts
|
||||
--- mock (storage folder) optional
|
||||
--- partials (optional)
|
||||
```
|
29
packages/server/express/test/_helper.ts
Normal file
29
packages/server/express/test/_helper.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Application } from 'express';
|
||||
import path from 'path';
|
||||
|
||||
import { parseConfigFile } from '@verdaccio/config';
|
||||
import { fileUtils } from '@verdaccio/core';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import { generateRandomHexString } from '@verdaccio/utils';
|
||||
|
||||
import apiMiddleware from '../src';
|
||||
|
||||
setup();
|
||||
|
||||
export const getConf = async (conf) => {
|
||||
const configPath = path.join(__dirname, 'config', conf);
|
||||
const config = parseConfigFile(configPath);
|
||||
// generate and create storage folder
|
||||
const storage = await fileUtils.createTempFolder('config');
|
||||
config.storage = storage;
|
||||
// custom config to avoid conflict with other tests
|
||||
config.auth.htpasswd.file = path.join(
|
||||
storage,
|
||||
`${config.auth.htpasswd.file}-${generateRandomHexString()}`
|
||||
);
|
||||
return config;
|
||||
};
|
||||
|
||||
export async function initializeServer(configName): Promise<Application> {
|
||||
return apiMiddleware(await getConf(configName));
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
storage: ./storage_default_storage
|
||||
plugins: ./plugins
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
|
||||
packages:
|
||||
'@public-anyone-can-publish/*':
|
||||
access: $anonymous jota_unpublish
|
||||
publish: $anonymous jota_unpublish
|
||||
unpublish: $anonymous jota_unpublish
|
||||
'@scope/deprecate':
|
||||
access: $all
|
||||
publish:
|
||||
- jota_deprecate
|
||||
- only_publish
|
||||
unpublish:
|
||||
- jota_deprecate
|
||||
- only_unpublish
|
||||
'@scope/starPackage':
|
||||
access: $all
|
||||
publish: jota_star
|
||||
unpublish: jota_star
|
||||
'@only-one-can-publish/*':
|
||||
access: jota_unpublish
|
||||
publish: jota_unpublish
|
||||
unpublish: jota_unpublish
|
||||
'@jquery/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'@scope/*':
|
||||
access: test
|
||||
publish: dsadsa
|
||||
proxy: npmjs
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: $authenticated
|
||||
proxy: npmjs
|
||||
'auth-package':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
'only-you-can-publish':
|
||||
access: $authenticated
|
||||
publish: you
|
||||
unpublish: you
|
||||
'non-unpublish':
|
||||
access: $authenticated
|
||||
publish: jota_unpublish_fail
|
||||
# There is some conditions to keep on mind here
|
||||
# - If unpublish is empty, fallback with the publish value
|
||||
# - If the user has permissions to publish and this empty it will be allowed to unpublish
|
||||
# - If we want to forbid anyone to unpublish, just write here any unexisting user
|
||||
unpublish: some_unexisting_user_defined_here_might_be_a_hash
|
||||
'only-unpublish':
|
||||
access: $authenticated
|
||||
# comment out is intended, we want to test if publish prop is not defined
|
||||
# publish: jota_unpublish_fail
|
||||
#
|
||||
unpublish:
|
||||
'super-admin-can-unpublish':
|
||||
access: $authenticated
|
||||
publish: super_admin
|
||||
unpublish: super_admin
|
||||
'all-can-unpublish':
|
||||
access: $authenticated
|
||||
publish: $all
|
||||
unpublish: $all
|
||||
'forbidden-place':
|
||||
access: nobody
|
||||
publish: $all
|
||||
'vue':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
proxy: npmjs
|
||||
'jquery':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: xxx
|
||||
proxy: npmjs
|
||||
log: { type: stdout, format: pretty, level: error }
|
@ -1,60 +0,0 @@
|
||||
const json = {
|
||||
_id: '@scope/pk1-test',
|
||||
name: '@scope/pk1-test',
|
||||
description: '',
|
||||
'dist-tags': {
|
||||
latest: '1.0.6',
|
||||
},
|
||||
versions: {
|
||||
'1.0.6': {
|
||||
name: '@scope/pk1-test',
|
||||
version: '1.0.6',
|
||||
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: '@scope/pk1-test@1.0.6',
|
||||
_npmVersion: '5.5.1',
|
||||
_nodeVersion: '8.7.0',
|
||||
_npmUser: {},
|
||||
dist: {
|
||||
integrity:
|
||||
'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjc' +
|
||||
'r9cmE6dUBf+XoPoH4g==',
|
||||
shasum: '2c03764f651a9f016ca0b7620421457b619151b9',
|
||||
tarball: 'http://localhost:5555/@scope/pk1-test/-/@scope/pk1-test-1.0.6.tgz',
|
||||
},
|
||||
},
|
||||
},
|
||||
readme: '# test',
|
||||
_attachments: {
|
||||
'@scope/pk1-test-1.0.6.tgz': {
|
||||
content_type: 'application/octet-stream',
|
||||
data:
|
||||
'H4sIAAAAAAAAE+2W32vbMBDH85y/QnjQp9qxLEeBMsbGlocNBmN7bFdQ5WuqxJaEpGQdo//79KPeQsnI' +
|
||||
'w5KUDX/9IOvurLuz/DHSjK/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1a' +
|
||||
'W8eML+Vv10m9oF/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0Sc' +
|
||||
'CdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y' +
|
||||
'7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yo' +
|
||||
'EHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS/pLQe+D+FIv/agIWI6GX66kFuIhT+' +
|
||||
'1gDjrp/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0/jWiAK8OcMjt8MW3OlfQppcuhhQ6k' +
|
||||
'+2OgkK2Q8DssFPi/IHpU9fz3/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6/f88f/Pu47zomiPk2Lv/dOv8' +
|
||||
'h+P/34/D/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=',
|
||||
length: 512,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = json;
|
@ -1,149 +0,0 @@
|
||||
// import { Package } from '@verdaccio/types';
|
||||
|
||||
// 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/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9c' +
|
||||
// 'mE6dUBf+XoPoH4g==',
|
||||
// shasum: '2c03764f651a9f016ca0b7620421457b619151b9', // pragma: allowlist secret
|
||||
// tarball: `http:\/\/localhost:5555\/${pkgName}\/-\/${pkgName}-${version}.tgz`,
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * The metadata that comes from npm unpublish only contains the versions won't be removed and
|
||||
// * also does not includes any _attachment.
|
||||
// * @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;
|
||||
// }, {});
|
||||
|
||||
// // @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,
|
||||
// };
|
||||
// }
|
||||
|
||||
// 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/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr' +
|
||||
// '9cmE6dUBf+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//79KPeQsnI' +
|
||||
// 'w5KUDX/9IOvurLuz/DHSjK/YAiY6jcXSKjk6sMqypHWNdtmD6hlBI0wqQmo8nVbVqMR4OsNoVB66kF1a' +
|
||||
// 'W8eML+Vv10m9oF/jP6IfY4QyyTrILlD2eqkcm+gVzpdrJrPz4NuAsULJ4MZFWdBkbcByI7R79CRjx0Sc' +
|
||||
// 'CdnAvf+SkjUFWu8IubzBgXUhDPidQlfZ3BhlLpBUKDiQ1cDFrYDmKkNnZwjuhUM4808+xNVW8P2bMk1Y' +
|
||||
// '7vJrtLC1u1MmLPjBF40+Cc4ahV6GDmI/DWygVRpMwVX3KtXUCg7Sxp7ff3nbt6TBFy65gK1iffsN41yo' +
|
||||
// 'EHtdFbOiisWMH8bPvXUH0SP3k+KG3UBr+DFy7OGfEJr4x5iWVeS/pLQe+D+FIv/agIWI6GX66kFuIhT+' +
|
||||
// '1gDjrp/4d7WAvAwEJPh0u14IufWkM0zaW2W6nLfM2lybgJ4LTJ0/jWiAK8OcMjt8MW3OlfQppcuhhQ6k' +
|
||||
// '+2OgkK2Q8DssFPi/IHpU9fz3/+xj5NjDf8QFE39VmE4JDfzPCBn4P4X6/f88f/Pu47zomiPk2Lv/dOv8' +
|
||||
// 'h+P/34/D/p9CL+Kp67mrGDRo0KBBp9ZPsETQegASAAA=',
|
||||
// length: 512,
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
// export function generateDeprecateMetadata(
|
||||
// pkgName: string,
|
||||
// version = '1.0.0',
|
||||
// deprecated: string = ''
|
||||
// ): Package {
|
||||
// const res = {
|
||||
// ...generatePackageMetadata(pkgName, version),
|
||||
// _attachments: {},
|
||||
// };
|
||||
// res.versions[version].deprecated = deprecated;
|
||||
// return res;
|
||||
// }
|
@ -1,10 +0,0 @@
|
||||
server_user_api_spec:3TdCV4iEpNFsI:autocreated 2020-11-08T10:36:37.581Z
|
||||
jota_unpublish:oIj/79.KRKO6Y:autocreated 2020-11-08T10:36:37.881Z
|
||||
jota_unpublish_fail:y7dutM1X0pByQ:autocreated 2020-11-08T10:36:37.934Z
|
||||
jota_only_unpublish_fail:3rUkLjiXInch.:autocreated 2020-11-08T10:36:37.947Z
|
||||
super_admin:yW2wIbTxWW1UA:autocreated 2020-11-08T10:36:37.953Z
|
||||
any_user:VBq3LIOEN9VOY:autocreated 2020-11-08T10:36:37.971Z
|
||||
jota_star:rp9KgzaAC2Uew:autocreated 2020-11-08T10:36:37.988Z
|
||||
jota_deprecate:Q09PY3eVq/L1E:autocreated 2020-11-08T10:36:38.012Z
|
||||
only_publish:s2pCXhzEgIupY:autocreated 2020-11-08T10:36:38.040Z
|
||||
only_unpublish:+JTPy3GKmGlEE:autocreated 2020-11-08T10:36:38.046Z
|
@ -1,756 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import path from 'path';
|
||||
import request from 'supertest';
|
||||
|
||||
import { API_MESSAGE, HEADERS, HEADER_TYPE, HTTP_STATUS, TOKEN_BEARER } from '@verdaccio/core';
|
||||
import { logger, setup } from '@verdaccio/logger';
|
||||
import { mockServer } from '@verdaccio/mock';
|
||||
import {
|
||||
DOMAIN_SERVERS,
|
||||
configExample,
|
||||
generateRamdonStorage,
|
||||
generateUnPublishURI,
|
||||
getNewToken,
|
||||
getPackage,
|
||||
putPackage,
|
||||
verifyPackageVersionDoesExist,
|
||||
} from '@verdaccio/mock';
|
||||
import { buildToken } from '@verdaccio/utils';
|
||||
|
||||
import endPointAPI from '../../src';
|
||||
import publishMetadata from './helpers/publish-api';
|
||||
import {
|
||||
generateDeprecateMetadata,
|
||||
generatePackageMetadata,
|
||||
generatePackageUnpublish,
|
||||
generateStarMedatada,
|
||||
generateVersion,
|
||||
} from './helpers/utils';
|
||||
|
||||
setup();
|
||||
|
||||
const credentials = { name: 'server_user_api_spec', password: 'secretPass' };
|
||||
|
||||
describe('endpoint unit test', () => {
|
||||
let app;
|
||||
let mockRegistry;
|
||||
|
||||
beforeAll(async function () {
|
||||
const store = generateRamdonStorage();
|
||||
const mockServerPort = 55549;
|
||||
const configForTest = configExample(
|
||||
{
|
||||
filters: {
|
||||
[path.join(__dirname, './plugin/filter')]: {
|
||||
pkg: 'npm_test',
|
||||
version: '2.0.0',
|
||||
},
|
||||
},
|
||||
storage: store,
|
||||
config_path: store,
|
||||
uplinks: {
|
||||
npmjs: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
'api.spec.yaml',
|
||||
__dirname
|
||||
);
|
||||
|
||||
app = await endPointAPI(configForTest);
|
||||
const binPath = require.resolve('verdaccio/bin/verdaccio');
|
||||
const storePath = path.join(__dirname, '/mock/store');
|
||||
mockRegistry = await mockServer(mockServerPort, { storePath, silence: true }).init(binPath);
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
const [registry, pid] = mockRegistry;
|
||||
registry.stop();
|
||||
logger.info(`registry ${pid} has been stopped`);
|
||||
});
|
||||
|
||||
describe('Registry API Endpoints', () => {
|
||||
describe('should test user api', () => {
|
||||
describe('should test authorization headers with tokens only errors', () => {
|
||||
test('should fails on protected endpoint /-/auth-package bad format', () => {
|
||||
return new Promise((resolve) => {
|
||||
request(app)
|
||||
.get('/auth-package')
|
||||
.set(HEADERS.AUTHORIZATION, 'FakeHader')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.FORBIDDEN)
|
||||
.end(function (err, res) {
|
||||
expect(res.body.error).toBeDefined();
|
||||
expect(res.body.error).toMatch(
|
||||
/authorization required to access package auth-package/
|
||||
);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should fails on protected endpoint /-/auth-package bad JWT Bearer format', (done) => {
|
||||
request(app)
|
||||
.get('/auth-package')
|
||||
.set(HEADERS.AUTHORIZATION, TOKEN_BEARER)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.FORBIDDEN)
|
||||
.end(function (err, res) {
|
||||
expect(res.body.error).toBeDefined();
|
||||
expect(res.body.error).toMatch(
|
||||
/authorization required to access package auth-package/
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should fails on protected endpoint /-/auth-package well JWT Bearer', (done) => {
|
||||
request(app)
|
||||
.get('/auth-package')
|
||||
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, '12345'))
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HTTP_STATUS.FORBIDDEN)
|
||||
.end(function (err, res) {
|
||||
expect(res.body.error).toBeDefined();
|
||||
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) {
|
||||
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 '${credentials.name}' created`);
|
||||
|
||||
// testing JWT auth headers with token
|
||||
// we need it here, because token is required
|
||||
request(app)
|
||||
.get('/vue')
|
||||
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function (err, res) {
|
||||
expect(err).toBeNull();
|
||||
expect(res.body).toBeDefined();
|
||||
expect(res.body.name).toMatch(/vue/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should test package api', () => {
|
||||
// The current behaviour depends of what's defined in the following configuration file.
|
||||
// test/unit/partials/config/yaml/api.spec.yaml
|
||||
// 'jquery':
|
||||
// access: $all
|
||||
// publish: $all
|
||||
// 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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(res.body).toBeDefined();
|
||||
expect(res.body.name).toMatch(/jquery/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(res.body).toBeDefined();
|
||||
expect(res.body.name).toMatch(/jquery/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(res.body).toBeDefined();
|
||||
expect(res.body.name).toMatch(/jquery/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('testing filters', () => {
|
||||
test('be able to filter packages', (done) => {
|
||||
request(app)
|
||||
.get('/npm_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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
// Filter out 2.0.0
|
||||
expect(Object.keys(res.body.versions)).toEqual(['1.0.0']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should not found when a filter fails', (done) => {
|
||||
request(app)
|
||||
// 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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(res.body).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should fetch a scoped tarball from remote uplink', (done) => {
|
||||
request(app)
|
||||
.get('/@jquery/jquery/-/jquery-1.5.1.tgz')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.OCTET_STREAM)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
console.log('err', err);
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(res.body).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
expect(err).not.toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should test search api', () => {
|
||||
test('should perform a search', (done) => {
|
||||
request(app)
|
||||
.get('/-/v1/search?text=npm7&size=2000&from=0&quality=1&popularity=0.1&maintenance=0.1')
|
||||
.set('accept-encoding', HEADERS.JSON)
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.expect(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function (err) {
|
||||
if (err) {
|
||||
expect(err).toBeNull();
|
||||
return done(err);
|
||||
}
|
||||
// TODO: we have to catch the stream check whether it returns something
|
||||
// we should not spend much time on this api since is deprecated somehow.
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should test publish/unpublish api', () => {
|
||||
/**
|
||||
* It publish 2 versions and unpublish the latest one, then verifies
|
||||
* the version do not exist anymore in the body of the metadata.
|
||||
*/
|
||||
const runPublishUnPublishFlow = async (pkgName: string, token?: string) => {
|
||||
const version = '2.0.0';
|
||||
const pkg = generatePackageMetadata(pkgName, version);
|
||||
|
||||
const [err] = await putPackage(request(app), `/${pkgName}`, pkg, token);
|
||||
if (err) {
|
||||
expect(err).toBeNull();
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
const newVersion = '2.0.1';
|
||||
const [newErr] = await putPackage(
|
||||
request(app),
|
||||
`/${pkgName}`,
|
||||
generatePackageMetadata(pkgName, newVersion),
|
||||
token
|
||||
);
|
||||
if (newErr) {
|
||||
expect(newErr).toBeNull();
|
||||
return Promise.reject(newErr);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
const existVersion = await verifyPackageVersionDoesExist(app, pkgName, newVersion, token);
|
||||
expect(existVersion).toBeTruthy();
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
describe('un/publish scenarios with credentials', () => {
|
||||
test('should flow with no credentials', async () => {
|
||||
const pkgName = '@public-anyone-can-publish/pk1-test';
|
||||
return await runPublishUnPublishFlow(pkgName, undefined);
|
||||
});
|
||||
|
||||
test('should flow with credentials', async () => {
|
||||
const credentials = { name: 'jota_unpublish', password: 'secretPass' };
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
const pkgName = '@only-one-can-publish/pk1-test';
|
||||
|
||||
return await runPublishUnPublishFlow(pkgName, token);
|
||||
});
|
||||
});
|
||||
|
||||
describe('test error handling', () => {
|
||||
test('should fail if user is not allowed to unpublish', async () => {
|
||||
/**
|
||||
* Context:
|
||||
*
|
||||
* 'non-unpublish':
|
||||
* access: $authenticated
|
||||
* publish: jota_unpublish_fail
|
||||
* # There is some conditions to keep on mind here
|
||||
* # - If unpublish is empty, fallback with the publish value
|
||||
* # - If the user has permissions to publish and this empty it will
|
||||
* # be allowed to unpublish
|
||||
* # - If we want to forbid anyone to unpublish, just write here any non-existing user
|
||||
* unpublish: none
|
||||
*
|
||||
* The result of this test should fail and even if jota_unpublish_fail is
|
||||
* allowed to publish.
|
||||
*
|
||||
*/
|
||||
const credentials = { name: 'jota_unpublish_fail', password: 'secretPass' };
|
||||
const pkgName = 'non-unpublish';
|
||||
const newVersion = '1.0.0';
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
|
||||
const [newErr] = await putPackage(
|
||||
request(app),
|
||||
`/${pkgName}`,
|
||||
generatePackageMetadata(pkgName, newVersion),
|
||||
token
|
||||
);
|
||||
if (newErr) {
|
||||
expect(newErr).toBeNull();
|
||||
return Promise.reject(newErr);
|
||||
}
|
||||
|
||||
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/
|
||||
);
|
||||
});
|
||||
|
||||
test('should fail if publish prop is not defined', async () => {
|
||||
/**
|
||||
* Context:
|
||||
*
|
||||
* 'non-unpublish':
|
||||
access: $authenticated
|
||||
publish: jota_unpublish_fail
|
||||
# There is some conditions to keep on mind here
|
||||
# - If unpublish is empty, fallback with the publish value
|
||||
# - If the user has permissions to publish and this empty it will be allowed to unpublish
|
||||
# - If we want to forbid anyone to unpublish, just write here any non-existing user
|
||||
unpublish: none
|
||||
|
||||
The result of this test should fail and even if jota_unpublish_fail is allowed
|
||||
to publish.
|
||||
|
||||
*
|
||||
*/
|
||||
const credentials = { name: 'jota_only_unpublish_fail', password: 'secretPass' };
|
||||
const pkgName = 'only-unpublish';
|
||||
const newVersion = '1.0.0';
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
|
||||
const [newErr, resp] = await putPackage(
|
||||
request(app),
|
||||
`/${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/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('should be able to publish/unpublish by only super_admin user', async () => {
|
||||
const credentials = { name: 'super_admin', password: 'secretPass' };
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
return new Promise((resolve, reject) => {
|
||||
request(app)
|
||||
.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',
|
||||
})
|
||||
)
|
||||
)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
expect(err).toBeNull();
|
||||
return reject(err);
|
||||
}
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.success).toBeDefined();
|
||||
expect(res.body.success).toBeTruthy();
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.PKG_CREATED);
|
||||
request(app)
|
||||
.del('/super-admin-can-unpublish/-rev/4-6abcdb4efd41a576')
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function (err, res) {
|
||||
expect(err).toBeNull();
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.PKG_REMOVED);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should be able to publish/unpublish by any user', async () => {
|
||||
const credentials = { name: 'any_user', password: 'secretPass' };
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
return new Promise((resolve, reject) => {
|
||||
request(app)
|
||||
.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',
|
||||
})
|
||||
)
|
||||
)
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
expect(err).toBeNull();
|
||||
return reject(err);
|
||||
}
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.success).toBeDefined();
|
||||
expect(res.body.success).toBeTruthy();
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.PKG_CREATED);
|
||||
request(app)
|
||||
.del('/all-can-unpublish/-rev/4-6abcdb4efd41a576')
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
|
||||
.expect(HTTP_STATUS.CREATED)
|
||||
.end(function (err, res) {
|
||||
expect(err).toBeNull();
|
||||
expect(res.body.ok).toBeDefined();
|
||||
expect(res.body.ok).toMatch(API_MESSAGE.PKG_REMOVED);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should test star and stars api', () => {
|
||||
const pkgName = '@scope/starPackage';
|
||||
const credentials = { name: 'jota_star', password: 'secretPass' };
|
||||
let token = '';
|
||||
beforeAll(async () => {
|
||||
token = await getNewToken(request(app), credentials);
|
||||
await putPackage(request(app), `/${pkgName}`, generatePackageMetadata(pkgName), token);
|
||||
});
|
||||
|
||||
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 retrieve stars list with credentials', async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
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 reject(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 reject(err);
|
||||
}
|
||||
expect(res.body.rows).toBeDefined();
|
||||
expect(res.body.rows).toHaveLength(1);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should test (un)deprecate api', () => {
|
||||
const pkgName = '@scope/deprecate';
|
||||
const credentials = { name: 'jota_deprecate', password: 'secretPass' };
|
||||
const version = '1.0.0';
|
||||
let token = '';
|
||||
beforeAll(async () => {
|
||||
token = await getNewToken(request(app), credentials);
|
||||
await putPackage(
|
||||
request(app),
|
||||
`/${pkgName}`,
|
||||
generatePackageMetadata(pkgName, version),
|
||||
token
|
||||
);
|
||||
});
|
||||
|
||||
test('should deprecate a package', async () => {
|
||||
const pkg = generateDeprecateMetadata(pkgName, version, 'get deprecated');
|
||||
const [err] = await putPackage(request(app), `/${pkgName}`, pkg, token);
|
||||
if (err) {
|
||||
expect(err).toBeNull();
|
||||
return Promise.reject(err);
|
||||
}
|
||||
const [, res] = await getPackage(request(app), '', pkgName);
|
||||
expect(res.body.versions[version].deprecated).toEqual('get deprecated');
|
||||
});
|
||||
|
||||
test('should undeprecate a package', async () => {
|
||||
let pkg = generateDeprecateMetadata(pkgName, version, 'get deprecated');
|
||||
await putPackage(request(app), `/${pkgName}`, pkg, token);
|
||||
pkg = generateDeprecateMetadata(pkgName, version, '');
|
||||
const [err] = await putPackage(request(app), `/${pkgName}`, pkg, token);
|
||||
if (err) {
|
||||
expect(err).toBeNull();
|
||||
return;
|
||||
}
|
||||
const [, res] = await getPackage(request(app), '', pkgName);
|
||||
expect(res.body.versions[version].deprecated).not.toBeDefined();
|
||||
});
|
||||
|
||||
test(
|
||||
'should require both publish and unpublish access to ' + '(un)deprecate a package',
|
||||
async () => {
|
||||
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), `/${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/
|
||||
);
|
||||
credentials = { name: 'only_unpublish', password: 'secretPass' };
|
||||
token = await getNewToken(request(app), credentials);
|
||||
const [err2, res2] = await putPackage(request(app), `/${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/
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
test('should deprecate multiple packages', async () => {
|
||||
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',
|
||||
};
|
||||
await putPackage(request(app), `/${pkgName}`, pkg, token);
|
||||
const [, res] = await getPackage(request(app), '', pkgName);
|
||||
return new Promise((resolve) => {
|
||||
expect(res.body.versions[version].deprecated).toEqual('get deprecated');
|
||||
expect(res.body.versions['1.0.1'].deprecated).toEqual('get deprecated');
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Binary file not shown.
@ -1,76 +0,0 @@
|
||||
{
|
||||
"name": "@jquery/jquery",
|
||||
"versions": {
|
||||
"1.5.1": {
|
||||
"name": "@jquery/jquery",
|
||||
"description": "jQuery: The Write Less, Do More, JavaScript Library",
|
||||
"url": "jquery.com",
|
||||
"keywords": [
|
||||
"util",
|
||||
"dom",
|
||||
"jquery"
|
||||
],
|
||||
"author": {
|
||||
"name": "John Resig",
|
||||
"email": "jeresig@gmail.com"
|
||||
},
|
||||
"contributors": [],
|
||||
"dependencies": {
|
||||
"jsdom": "=0.1.20",
|
||||
"htmlparser": ">= 1.7.3"
|
||||
},
|
||||
"lib": "lib",
|
||||
"main": "./dist/node-jquery.js",
|
||||
"version": "1.5.1",
|
||||
"_id": "@jquery/jquery@1.5.1",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"_engineSupported": true,
|
||||
"_npmVersion": "0.3.15",
|
||||
"_nodeVersion": "v0.4.2",
|
||||
"directories": {
|
||||
"lib": "./lib"
|
||||
},
|
||||
"files": [
|
||||
""
|
||||
],
|
||||
"_defaultsLoaded": true,
|
||||
"dist": {
|
||||
"shasum": "2ae2d661e906c1a01e044a71bb5b2743942183e5",
|
||||
"tarball": "https://registry.npmjs.org/@jquery%2jquery/-/jquery-1.5.1.tgz"
|
||||
},
|
||||
"deprecated": "Versions of the jquery npm package older than 1.9.0 are patched versions that don't work in web browsers. Please upgrade to >=1.11.0."
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"modified": "2018-05-21T21:39:54.702Z",
|
||||
"created": "2011-03-19T07:19:56.392Z",
|
||||
"1.5.1": "2011-03-19T07:19:56.956Z"
|
||||
},
|
||||
"dist-tags": {
|
||||
"beta": "3.0.0",
|
||||
"latest": "3.3.1",
|
||||
"jota": "1.6.3"
|
||||
},
|
||||
"_uplinks": {
|
||||
"npmjs": {
|
||||
"etag": "W/\"252f0a131cedd3ea82dfefd6fa049558\"",
|
||||
"fetched": 1529779934081
|
||||
}
|
||||
},
|
||||
"_distfiles": {
|
||||
"jquery-1.5.1.tgz": {
|
||||
"url": "https://registry.npmjs.org/@jquery%2jquery/-/jquery-1.5.1.tgz",
|
||||
"sha": "2ae2d661e906c1a01e044a71bb5b2743942183e5",
|
||||
"registry": "npmjs"
|
||||
}
|
||||
},
|
||||
"_attachments": {
|
||||
"jquery-1.5.1.tgz": {
|
||||
"shasum": "2ae2d661e906c1a01e044a71bb5b2743942183e5"
|
||||
}
|
||||
},
|
||||
"_rev": "60-fed4915c27b9c1e6",
|
||||
"readme": "# jQuery\n\n> jQuery is a fast, small, and feature-rich JavaScript library.\n\nFor information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/).\nFor source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).\n\nIf upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.\n\n## Including jQuery\n\nBelow are some of the most common ways to include jQuery.\n\n### Browser\n\n#### Script tag\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.3.1.min.js\"></script>\n```\n\n#### Babel\n\n[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.\n\n```js\nimport $ from \"jquery\";\n```\n\n#### Browserify/Webpack\n\nThere are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this...\n\n```js\nvar $ = require(\"jquery\");\n```\n\n#### AMD (Asynchronous Module Definition)\n\nAMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html).\n\n```js\ndefine([\"jquery\"], function($) {\n\n});\n```\n\n### Node\n\nTo include jQuery in [Node](nodejs.org), first install with npm.\n\n```sh\nnpm install jquery\n```\n\nFor jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.\n\n```js\nrequire(\"jsdom\").env(\"\", function(err, window) {\n\tif (err) {\n\t\tconsole.error(err);\n\t\treturn;\n\t}\n\n\tvar $ = require(\"jquery\")(window);\n});\n```"
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "corrupted-package"
|
||||
"version": {},
|
||||
"dist-tags": {},
|
||||
"_distfiles": {},
|
||||
"_attachments": {},
|
||||
"_uplinks": {},
|
||||
"time": {},
|
||||
"_rev": "0-0000000000000000",
|
||||
"readme": "",
|
||||
"versions": {}
|
||||
}
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,75 +0,0 @@
|
||||
{
|
||||
"_id": "npm_test",
|
||||
"name": "npm_test",
|
||||
"description": "",
|
||||
"dist-tags": {
|
||||
"latest": "1.0.0"
|
||||
},
|
||||
"versions": {
|
||||
"1.0.0": {
|
||||
"name": "npm_test",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"test": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "npm_test@1.0.0",
|
||||
"_npmVersion": "5.5.1",
|
||||
"_nodeVersion": "9.3.0",
|
||||
"_npmUser": {},
|
||||
"dist": {
|
||||
"integrity": "sha512-tfzM1OFjWwg2d2Wke/DV6icjeTZUVOZYLkbf8wmONRSAgMovL/F+zyI24OhTtWyOXd1Kbj2YUMBvLpmpAjv8zg==",
|
||||
"shasum": "3e4e6bd5097b295e520b947c9be3259a9509a673",
|
||||
"tarball": "http://localhost:4873/npm_test/-/npm_test-1.0.0.tgz"
|
||||
}
|
||||
},
|
||||
"2.0.0": {
|
||||
"name": "npm_test",
|
||||
"version": "2.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"test": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "npm_test@2.0.0",
|
||||
"_npmVersion": "5.5.1",
|
||||
"_nodeVersion": "9.3.0",
|
||||
"_npmUser": {},
|
||||
"dist": {
|
||||
"integrity": "sha512-tzzM1OFjWwg2d2Wke/DV6icjeTZUVOZYLkbf8wmONRSAgMovL/F+zyI24OhTtWyOXd1Kbj2YUMBvLpmpAjv8zg==",
|
||||
"shasum": "3a4e6bd5097b295e520b947c9be3259a9509a673",
|
||||
"tarball": "http://localhost:4873/npm_test/-/npm_test-2.0.0.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_attachments": {
|
||||
"npm_test-1.0.0.tgz": {
|
||||
"content_type": "application/octet-stream",
|
||||
"data": "H4sIAAAAAAAAE+2ST08CMRDFOe+nmPTAyawt7ELCVT149ihqmu4gI9I2bUGM4bvbbhGM4eYmxmR/l6bvtW+mf6xUK/mMlzaP5Ys3etAxnPNJVcE5PVHV0RPjkairsZiK0YALUU+mMOBdN3KOjQ/SxVZ+m5PPAsfxn/BRADAt18hmwDxpY0k+BfSBXSRni86T0ckUJS95Vhv0ypENByeLa0ntjHSDu/iPvpZajIJWhD66qRwcC6Xlj6KsYm7U94cN2+sfe7KRS34LabuMCaiWBubsxjnjZqANJAO8RUULwmbOYDgE3FEAcSqzwvc345oUd//QKnITlsadzvNKCrVv7+X27ooV++Kv36qnp6enSz4B8bhKUwAIAAA=",
|
||||
"length": 281
|
||||
},
|
||||
"npm_test-2.0.0.tgz": {
|
||||
"content_type": "application/octet-stream",
|
||||
"data": "H4sIAAAAAAAAE+2ST08CMRDFOe+nmPTAyawt7ELCVT149ihqmu4gI9I2bUGM4bvbbhGM4eYmxmR/l6bvtW+mf6xUK/mMlzaP5Ys3etAxnPNJVcE5PVHV0RPjkairsZiK0YALUU+mMOBdN3KOjQ/SxVZ+m5PPAsfxn/BRADAt18hmwDxpY0k+BfSBXSRni86T0ckUJS95Vhv0ypENByeLa0ntjHSDu/iPvpZajIJWhD66qRwcC6Xlj6KsYm7U94cN2+sfe7KRS34LabuMCaiWBubsxjnjZqANJAO8RUULwmbOYDgE3FEAcSqzwvc345oUd//QKnITlsadzvNKCrVv7+X27ooV++Kv36qnp6enSz4B8bhKUwAIAAA=",
|
||||
"length": 281
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1,25 +0,0 @@
|
||||
class FilterPlugin {
|
||||
private _config;
|
||||
public constructor(config) {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
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') {
|
||||
reject(new Error('Example filter failure'));
|
||||
return;
|
||||
}
|
||||
// Example filter that removes a single blocked package
|
||||
if (this._config.pkg === pkg.name) {
|
||||
// In reality, we also want to remove references in attachments and dist-tags,
|
||||
// etc. This is just a POC
|
||||
delete pkg.versions[this._config.version];
|
||||
}
|
||||
resolve(pkg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
exports.default = FilterPlugin;
|
@ -1,14 +0,0 @@
|
||||
store:
|
||||
memory:
|
||||
limit: 1000
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: http://localhost:4873/
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
'*':
|
||||
access: $all
|
||||
publish: $all
|
||||
log: { type: stdout, format: pretty, level: warn }
|
@ -1,64 +0,0 @@
|
||||
// import express from 'express';
|
||||
// import path from 'path';
|
||||
|
||||
// // import request from 'request';
|
||||
// import { parseConfigFile } from '@verdaccio/config';
|
||||
// import { API_ERROR } from '@verdaccio/core';
|
||||
// import { setup } from '@verdaccio/logger';
|
||||
|
||||
// import endPointAPI from '../../src';
|
||||
|
||||
// setup([{ type: 'stdout', format: 'pretty', level: 'trace' }]);
|
||||
|
||||
// const app = express();
|
||||
// const server = require('http').createServer(app);
|
||||
|
||||
// const parseConfigurationFile = (conf) => {
|
||||
// return path.join(__dirname, `./${conf}`);
|
||||
// };
|
||||
|
||||
// // TODO: restore when web module is ready
|
||||
// describe.skip('basic system test', () => {
|
||||
// let port;
|
||||
// jest.setTimeout(20000);
|
||||
|
||||
// beforeAll(async function (done) {
|
||||
// const config = parseConfigFile(parseConfigurationFile('basic.yaml'));
|
||||
// app.use(await endPointAPI(config));
|
||||
// server.listen(0, function () {
|
||||
// port = server.address().port;
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
// afterAll((done) => {
|
||||
// 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 /___not_found_package', (done) => {
|
||||
// request(
|
||||
// {
|
||||
// json: true,
|
||||
// url: `http://localhost:${port}/___not_found_package`,
|
||||
// },
|
||||
// function (err, res, body) {
|
||||
// expect(err).toBeNull();
|
||||
// expect(body.error).toMatch(API_ERROR.NO_PACKAGE);
|
||||
// done();
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
// });
|
28
packages/server/express/test/config/conf.yaml
Normal file
28
packages/server/express/test/config/conf.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
# storage: this is generated on _helper file
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd-package
|
||||
|
||||
web:
|
||||
enable: true
|
||||
title: verdaccio
|
||||
|
||||
publish:
|
||||
allow_offline: false
|
||||
|
||||
uplinks:
|
||||
|
||||
log: { type: stdout, format: pretty, level: trace }
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
'**':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
|
||||
_debug: true
|
26
packages/server/express/test/config/no_debug.yaml
Normal file
26
packages/server/express/test/config/no_debug.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
# storage: this is generated on _helper file
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd-package
|
||||
|
||||
web:
|
||||
enable: true
|
||||
title: verdaccio
|
||||
|
||||
publish:
|
||||
allow_offline: false
|
||||
|
||||
uplinks:
|
||||
|
||||
log: { type: stdout, format: pretty, level: trace }
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
'**':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
29
packages/server/express/test/config/powered-custom.yaml
Normal file
29
packages/server/express/test/config/powered-custom.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
# storage: this is generated on _helper file
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd-package
|
||||
|
||||
web:
|
||||
enable: true
|
||||
|
||||
user_agent: 'custom user agent'
|
||||
|
||||
publish:
|
||||
allow_offline: false
|
||||
|
||||
uplinks:
|
||||
|
||||
log: { type: stdout, format: pretty, level: trace }
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
'**':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
|
||||
_debug: true
|
29
packages/server/express/test/config/powered-disabled.yaml
Normal file
29
packages/server/express/test/config/powered-disabled.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
# storage: this is generated on _helper file
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd-package
|
||||
|
||||
web:
|
||||
enable: true
|
||||
|
||||
user_agent: false
|
||||
|
||||
publish:
|
||||
allow_offline: false
|
||||
|
||||
uplinks:
|
||||
|
||||
log: { type: stdout, format: pretty, level: trace }
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
'**':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
|
||||
_debug: true
|
27
packages/server/express/test/config/web-disabled.yaml
Normal file
27
packages/server/express/test/config/web-disabled.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
# storage: this is generated on _helper file
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd-package
|
||||
|
||||
web:
|
||||
enable: false
|
||||
|
||||
publish:
|
||||
allow_offline: false
|
||||
|
||||
uplinks:
|
||||
|
||||
log: { type: stdout, format: pretty, level: trace }
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
'**':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: none
|
||||
|
||||
_debug: true
|
@ -1,100 +0,0 @@
|
||||
import path from 'path';
|
||||
import request from 'supertest';
|
||||
|
||||
import { HEADERS, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { logger, setup } from '@verdaccio/logger';
|
||||
import { DOMAIN_SERVERS, configExample, generateRamdonStorage, mockServer } from '@verdaccio/mock';
|
||||
|
||||
import endPointAPI from '../../src';
|
||||
|
||||
setup([]);
|
||||
|
||||
describe('api with no limited access configuration', () => {
|
||||
let app;
|
||||
let mockRegistry;
|
||||
const store = generateRamdonStorage();
|
||||
jest.setTimeout(10000);
|
||||
|
||||
beforeAll(async () => {
|
||||
const mockServerPort = 55530;
|
||||
const configForTest = configExample(
|
||||
{
|
||||
config_path: store,
|
||||
uplinks: {
|
||||
remote: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
'pkg.access.yaml',
|
||||
__dirname
|
||||
);
|
||||
|
||||
app = await endPointAPI(configForTest);
|
||||
const binPath = require.resolve('verdaccio/bin/verdaccio');
|
||||
const storePath = path.join(__dirname, '/mock/store');
|
||||
mockRegistry = await mockServer(mockServerPort, { storePath, silence: true }).init(binPath);
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
const [registry, pid] = mockRegistry;
|
||||
registry.stop();
|
||||
logger.info(`registry ${pid} has been stopped`);
|
||||
});
|
||||
|
||||
describe('test proxy packages partially restricted', () => {
|
||||
test('should test fails on fetch endpoint /-/not-found', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(app)
|
||||
// @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) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should test fetch endpoint /-/jquery', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(app)
|
||||
// @ts-ignore
|
||||
.get('/jquery')
|
||||
.set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADERS.CONTENT_TYPE, /json/)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should success on fetch endpoint /-/vue', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(app)
|
||||
// @ts-ignore
|
||||
.get('/vue')
|
||||
.set(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HEADERS.CONTENT_TYPE, /json/)
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,12 +0,0 @@
|
||||
storage: ./storage_default_storage
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
proxy: remote
|
||||
'**':
|
||||
access: $all
|
||||
proxy: remote
|
||||
log: { type: stdout, format: pretty, level: warn }
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
JotaJWT:$2a$10$60jPnwXijJr7e/xU49JONenD4bnCm6mkRs4ZmzFaA1FpaBTV04VX2:autocreated 2022-07-20T21:24:34.547Z
|
||||
userTest2000:$2a$10$RIDJ4feTv9UmerS8e/dNRegCVr8PZlyDMajWLc3vs2V5golf6p6HS:autocreated 2022-07-20T21:24:34.861Z
|
||||
|
||||
userTest2001:$2a$10$RIx44sAe6pJNFZH.iFehpehD2GOnfGMKB3Vfqx428ScbdBDPGcPc2:autocreated 2022-07-20T21:24:34.926Z
|
||||
userTest2002:$2a$10$OMXRuM3/r2HWwQhghqBMt.LGOKfCqFtMPAgpQ1W5n/arL7ofZZJjG:autocreated 2022-07-20T21:24:35.053Z
|
@ -1,129 +0,0 @@
|
||||
import path from 'path';
|
||||
import request from 'supertest';
|
||||
|
||||
import { API_ERROR, HTTP_STATUS, SUPPORT_ERRORS } from '@verdaccio/core';
|
||||
import { logger, setup } from '@verdaccio/logger';
|
||||
import { mockServer } from '@verdaccio/mock';
|
||||
import {
|
||||
DOMAIN_SERVERS,
|
||||
configExample,
|
||||
generateRamdonStorage,
|
||||
getNewToken,
|
||||
getProfile,
|
||||
postProfile,
|
||||
} from '@verdaccio/mock';
|
||||
|
||||
import endPointAPI from '../../src';
|
||||
|
||||
setup([]);
|
||||
|
||||
describe('endpoint user profile', () => {
|
||||
let app;
|
||||
let mockRegistry;
|
||||
jest.setTimeout(20000);
|
||||
|
||||
beforeAll(async () => {
|
||||
const store = generateRamdonStorage();
|
||||
const mockServerPort = 55544;
|
||||
const configForTest = configExample(
|
||||
{
|
||||
storage: store,
|
||||
uplinks: {
|
||||
remote: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
},
|
||||
},
|
||||
config_path: store,
|
||||
},
|
||||
'profile.yaml',
|
||||
__dirname
|
||||
);
|
||||
|
||||
app = await endPointAPI(configForTest);
|
||||
const binPath = require.resolve('verdaccio/bin/verdaccio');
|
||||
const storePath = path.join(__dirname, '/mock/store');
|
||||
mockRegistry = await mockServer(mockServerPort, { storePath, silence: true }).init(binPath);
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
const [registry, pid] = mockRegistry;
|
||||
registry.stop();
|
||||
logger.info(`registry ${pid} has been stopped`);
|
||||
});
|
||||
|
||||
test('should fetch a profile of logged user', async () => {
|
||||
const credentials = { name: 'JotaJWT', password: 'secretPass' };
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
const [err1, res1] = await getProfile(request(app), token);
|
||||
expect(err1).toBeNull();
|
||||
expect(res1.body.name).toBe(credentials.name);
|
||||
});
|
||||
|
||||
describe('change password', () => {
|
||||
test('should change password successfully', async () => {
|
||||
const credentials = { name: 'userTest2000', password: 'secretPass000' };
|
||||
const body = {
|
||||
password: {
|
||||
new: '12345678',
|
||||
old: credentials.password,
|
||||
},
|
||||
};
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
const [err1, res1] = await postProfile(request(app), body, token);
|
||||
|
||||
expect(err1).toBeNull();
|
||||
expect(res1.body.name).toBe(credentials.name);
|
||||
});
|
||||
|
||||
test('should change password is too short', async () => {
|
||||
const credentials = { name: 'userTest2001', password: 'secretPass001' };
|
||||
const body = {
|
||||
password: {
|
||||
new: 'p1',
|
||||
old: credentials.password,
|
||||
},
|
||||
};
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
const [, resp] = await postProfile(request(app), body, token, HTTP_STATUS.UNAUTHORIZED);
|
||||
|
||||
expect(resp.error).not.toBeNull();
|
||||
/* eslint new-cap: 0 */
|
||||
expect(resp.error.text).toMatch(API_ERROR.PASSWORD_SHORT());
|
||||
});
|
||||
});
|
||||
|
||||
describe('change tfa', () => {
|
||||
test('should report TFA is disabled', async () => {
|
||||
const credentials = { name: 'userTest2002', password: 'secretPass002' };
|
||||
const body = {
|
||||
tfa: {},
|
||||
};
|
||||
const token = await getNewToken(request(app), credentials);
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
test('should forbid to fetch a profile with invalid token', async () => {
|
||||
const [, resp] = await getProfile(request(app), `fakeToken`, HTTP_STATUS.UNAUTHORIZED);
|
||||
|
||||
expect(resp.error).not.toBeNull();
|
||||
expect(resp.error.text).toMatch(API_ERROR.MUST_BE_LOGGED);
|
||||
});
|
||||
|
||||
test('should forbid to update a profile with invalid token', async () => {
|
||||
const [, resp] = await postProfile(request(app), {}, `fakeToken`, HTTP_STATUS.UNAUTHORIZED);
|
||||
|
||||
expect(resp.error).not.toBeNull();
|
||||
expect(resp.error.text).toMatch(API_ERROR.MUST_BE_LOGGED);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,21 +0,0 @@
|
||||
storage: ./storage
|
||||
plugins: ./plugins
|
||||
web:
|
||||
title: Verdaccio
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
security:
|
||||
api:
|
||||
jwt:
|
||||
sign:
|
||||
expiresIn: 10m
|
||||
notBefore: 0
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
'**':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
log: { type: stdout, format: pretty, level: warn }
|
113
packages/server/express/test/server.spec.ts
Normal file
113
packages/server/express/test/server.spec.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import supertest from 'supertest';
|
||||
|
||||
import { API_ERROR, HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
|
||||
|
||||
import { initializeServer } from './_helper';
|
||||
|
||||
test('should request any package', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
await supertest(app)
|
||||
.get('/jquery')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.NOT_FOUND);
|
||||
});
|
||||
|
||||
test('should able to catch non defined routes with 404', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
await supertest(app)
|
||||
.get('/-/this-does-not-exist-anywhere')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.NOT_FOUND);
|
||||
});
|
||||
|
||||
test('should return index page if web is enabled', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
const response = await supertest(app)
|
||||
.get('/')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_HTML_UTF8)
|
||||
.expect(HEADER_TYPE.CONTENT_ENCODING, HEADERS.GZIP)
|
||||
.expect(HTTP_STATUS.OK);
|
||||
expect(response.text).toMatch('<title>verdaccio</title>');
|
||||
});
|
||||
|
||||
test('should define rate limit headers', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
await supertest(app)
|
||||
.get('/')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_HTML_UTF8)
|
||||
.expect('x-ratelimit-limit', '10000')
|
||||
.expect('x-ratelimit-remaining', '9999')
|
||||
.expect(HTTP_STATUS.OK);
|
||||
});
|
||||
|
||||
test('should contains cors headers', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
await supertest(app).get('/').expect('access-control-allow-origin', '*').expect(HTTP_STATUS.OK);
|
||||
});
|
||||
|
||||
test('should contains etag', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
const response = await supertest(app)
|
||||
.get('/')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_HTML_UTF8)
|
||||
.expect(HTTP_STATUS.OK);
|
||||
const etag = response.get(HEADERS.ETAG);
|
||||
expect(typeof etag === 'string').toBeTruthy();
|
||||
});
|
||||
|
||||
test('should contains powered by header', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
const response = await supertest(app)
|
||||
.get('/')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_HTML_UTF8)
|
||||
.expect(HTTP_STATUS.OK);
|
||||
const powered = response.get('x-powered-by');
|
||||
expect(powered).toMatch('verdaccio/6');
|
||||
});
|
||||
|
||||
test('should not contains powered header', async () => {
|
||||
const app = await initializeServer('powered-disabled.yaml');
|
||||
const response = await supertest(app)
|
||||
.get('/')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_HTML_UTF8)
|
||||
.expect(HTTP_STATUS.OK);
|
||||
const powered = response.get('x-powered-by');
|
||||
expect(powered).toEqual('hidden');
|
||||
});
|
||||
|
||||
test('should contains custom powered header', async () => {
|
||||
const app = await initializeServer('powered-custom.yaml');
|
||||
const response = await supertest(app)
|
||||
.get('/')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_HTML_UTF8)
|
||||
.expect(HTTP_STATUS.OK);
|
||||
const powered = response.get('x-powered-by');
|
||||
expect(powered).toEqual('custom user agent');
|
||||
});
|
||||
|
||||
test('should return 404 if web is disabled', async () => {
|
||||
const app = await initializeServer('web-disabled.yaml');
|
||||
const response = await supertest(app)
|
||||
.get('/')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.NOT_FOUND);
|
||||
expect(response.body.error).toEqual(API_ERROR.WEB_DISABLED);
|
||||
});
|
||||
|
||||
test('should not display debug hook disabled by default', async () => {
|
||||
const app = await initializeServer('no_debug.yaml');
|
||||
await supertest(app)
|
||||
.get('/-/_debug')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.NOT_FOUND);
|
||||
});
|
||||
|
||||
test('should display debug hook if directly enabled', async () => {
|
||||
const app = await initializeServer('conf.yaml');
|
||||
const res = await supertest(app)
|
||||
.get('/-/_debug')
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(HTTP_STATUS.OK);
|
||||
expect(res.body.pid).toEqual(process.pid);
|
||||
expect(res.body.mem).toBeDefined();
|
||||
});
|
@ -1,219 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { Writable } from 'stream';
|
||||
|
||||
import { Config as AppConfig } from '@verdaccio/config';
|
||||
import { API_ERROR, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { logger, setup } from '@verdaccio/logger';
|
||||
import { DOMAIN_SERVERS, configExample, generateRamdonStorage, mockServer } from '@verdaccio/mock';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { Config } from '@verdaccio/types';
|
||||
|
||||
setup([]);
|
||||
|
||||
const mockServerPort = 55548;
|
||||
|
||||
const generateStorage = async function () {
|
||||
const storagePath = generateRamdonStorage();
|
||||
const storageConfig = configExample(
|
||||
{
|
||||
config_path: storagePath,
|
||||
storage: storagePath,
|
||||
uplinks: {
|
||||
npmjs: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
'store.spec.yaml',
|
||||
__dirname
|
||||
);
|
||||
|
||||
const config: Config = new AppConfig(storageConfig);
|
||||
const store: Storage = new Storage(config);
|
||||
await store.init(config, []);
|
||||
|
||||
return store;
|
||||
};
|
||||
|
||||
const generateSameUplinkStorage = async function () {
|
||||
const storagePath = generateRamdonStorage();
|
||||
const storageConfig = configExample(
|
||||
{
|
||||
config_path: storagePath,
|
||||
storage: storagePath,
|
||||
packages: {
|
||||
jquery: {
|
||||
access: ['$all'],
|
||||
publish: ['$all'],
|
||||
proxy: ['cached'],
|
||||
},
|
||||
'@jquery/*': {
|
||||
access: ['$all'],
|
||||
publish: ['$all'],
|
||||
proxy: ['notcached'],
|
||||
},
|
||||
},
|
||||
uplinks: {
|
||||
cached: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
cache: true,
|
||||
},
|
||||
notcached: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
cache: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
'store.spec.yaml',
|
||||
__dirname
|
||||
);
|
||||
|
||||
const config: Config = new AppConfig(storageConfig);
|
||||
const store: Storage = new Storage(config);
|
||||
await store.init(config, []);
|
||||
|
||||
return store;
|
||||
};
|
||||
|
||||
const createNullStream = () =>
|
||||
new Writable({
|
||||
write: function (chunk, encoding, next) {
|
||||
next();
|
||||
},
|
||||
});
|
||||
|
||||
describe('StorageTest', () => {
|
||||
let mockRegistry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const binPath = require.resolve('verdaccio/bin/verdaccio');
|
||||
const storePath = path.join(__dirname, '/mock/store');
|
||||
mockRegistry = await mockServer(mockServerPort, { storePath, silence: true }).init(binPath);
|
||||
return;
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
const [registry, pid] = mockRegistry;
|
||||
registry.stop();
|
||||
logger.info(`registry ${pid} has been stopped`);
|
||||
});
|
||||
|
||||
test('should be defined', async () => {
|
||||
const storage: Storage = await generateStorage();
|
||||
|
||||
expect(storage).toBeDefined();
|
||||
});
|
||||
|
||||
describe('test getTarball', () => {
|
||||
test.skip(
|
||||
'should select right uplink given package.proxy for' + ' upstream tarballs',
|
||||
async (done) => {
|
||||
const storage: Storage = await generateSameUplinkStorage();
|
||||
const notcachedSpy = jest.spyOn(storage.uplinks.notcached, 'fetchTarball');
|
||||
const cachedSpy = jest.spyOn(storage.uplinks.cached, 'fetchTarball');
|
||||
|
||||
await new Promise((res, rej) => {
|
||||
const reader = storage.getTarball('jquery', 'jquery-1.5.1.tgz');
|
||||
reader.on('end', () => {
|
||||
expect(notcachedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(cachedSpy).toHaveBeenCalledTimes(1);
|
||||
expect(cachedSpy).toHaveBeenCalledWith(
|
||||
'http://localhost:55548/jquery/-/jquery-1.5.1.tgz'
|
||||
);
|
||||
res();
|
||||
});
|
||||
reader.on('error', (err) => {
|
||||
rej(err);
|
||||
});
|
||||
reader.pipe(createNullStream());
|
||||
});
|
||||
|
||||
// Reset counters.
|
||||
cachedSpy.mockClear();
|
||||
notcachedSpy.mockClear();
|
||||
|
||||
await new Promise((res, rej) => {
|
||||
const reader = storage.getTarball('@jquery/jquery', 'jquery-1.5.1.tgz');
|
||||
reader.on('end', () => {
|
||||
expect(cachedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(notcachedSpy).toHaveBeenCalledTimes(1);
|
||||
expect(notcachedSpy).toHaveBeenCalledWith(
|
||||
'http://localhost:55548/@jquery%2fjquery/-/jquery-1.5.1.tgz'
|
||||
);
|
||||
res();
|
||||
});
|
||||
reader.on('error', (err) => {
|
||||
rej(err);
|
||||
});
|
||||
reader.pipe(createNullStream());
|
||||
});
|
||||
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('test _syncUplinksMetadata', () => {
|
||||
test('should fetch from uplink jquery metadata from registry', async () => {
|
||||
const storage: Storage = await generateStorage();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
storage._syncUplinksMetadata('jquery', null, {}, (err, metadata) => {
|
||||
expect(err).toBeNull();
|
||||
expect(metadata).toBeDefined();
|
||||
expect(metadata).toBeInstanceOf(Object);
|
||||
resolve(metadata);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should fails on fetch from uplink non existing from registry', async () => {
|
||||
const storage: Storage = await generateStorage();
|
||||
return new Promise((resolve) => {
|
||||
storage._syncUplinksMetadata('@verdaccio/404', null, {}, (err, _metadata, errors) => {
|
||||
expect(err).not.toBeNull();
|
||||
expect(errors).toBeInstanceOf(Array);
|
||||
expect(errors[0][0].statusCode).toBe(HTTP_STATUS.NOT_FOUND);
|
||||
expect(errors[0][0].message).toMatch(API_ERROR.NOT_PACKAGE_UPLINK);
|
||||
resolve(errors);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should fails on fetch from uplink corrupted pkg from registry', async () => {
|
||||
const storage: Storage = await generateStorage();
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
storage._syncUplinksMetadata('corrupted-package', null, {}, (err, metadata, errors) => {
|
||||
expect(err).not.toBeNull();
|
||||
expect(errors).toBeInstanceOf(Array);
|
||||
expect(errors[0][0].statusCode).toBe(HTTP_STATUS.INTERNAL_ERROR);
|
||||
expect(errors[0][0].message).toMatch(API_ERROR.BAD_STATUS_CODE);
|
||||
resolve(errors);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.skip('should not touch if the package exists and has no uplinks', async (done) => {
|
||||
const storagePath = generateRamdonStorage();
|
||||
const storage: Storage = (await generateStorage()) as Storage;
|
||||
const metadataSource = path.join(__dirname, '../../partials/metadata');
|
||||
const metadataPath = path.join(storagePath, 'npm_test/package.json');
|
||||
|
||||
fs.mkdirSync(path.join(storagePath, 'npm_test'));
|
||||
fs.writeFileSync(metadataPath, fs.readFileSync(metadataSource));
|
||||
const metadata = JSON.parse(fs.readFileSync(metadataPath).toString());
|
||||
// @ts-ignore
|
||||
storage.localStorage.updateVersions = jest.fn(storage.localStorage.updateVersions);
|
||||
expect(metadata).toBeDefined();
|
||||
storage._syncUplinksMetadata('npm_test', metadata, {}, (err) => {
|
||||
expect(err).toBeNull();
|
||||
// @ts-ignore
|
||||
expect(storage.localStorage.updateVersions).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Binary file not shown.
@ -1,76 +0,0 @@
|
||||
{
|
||||
"name": "@jquery/jquery",
|
||||
"versions": {
|
||||
"1.5.1": {
|
||||
"name": "@jquery/jquery",
|
||||
"description": "jQuery: The Write Less, Do More, JavaScript Library",
|
||||
"url": "jquery.com",
|
||||
"keywords": [
|
||||
"util",
|
||||
"dom",
|
||||
"jquery"
|
||||
],
|
||||
"author": {
|
||||
"name": "John Resig",
|
||||
"email": "jeresig@gmail.com"
|
||||
},
|
||||
"contributors": [],
|
||||
"dependencies": {
|
||||
"jsdom": "=0.1.20",
|
||||
"htmlparser": ">= 1.7.3"
|
||||
},
|
||||
"lib": "lib",
|
||||
"main": "./dist/node-jquery.js",
|
||||
"version": "1.5.1",
|
||||
"_id": "@jquery/jquery@1.5.1",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"_engineSupported": true,
|
||||
"_npmVersion": "0.3.15",
|
||||
"_nodeVersion": "v0.4.2",
|
||||
"directories": {
|
||||
"lib": "./lib"
|
||||
},
|
||||
"files": [
|
||||
""
|
||||
],
|
||||
"_defaultsLoaded": true,
|
||||
"dist": {
|
||||
"shasum": "2ae2d661e906c1a01e044a71bb5b2743942183e5",
|
||||
"tarball": "https://registry.npmjs.org/@jquery%2jquery/-/jquery-1.5.1.tgz"
|
||||
},
|
||||
"deprecated": "Versions of the jquery npm package older than 1.9.0 are patched versions that don't work in web browsers. Please upgrade to >=1.11.0."
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"modified": "2018-05-21T21:39:54.702Z",
|
||||
"created": "2011-03-19T07:19:56.392Z",
|
||||
"1.5.1": "2011-03-19T07:19:56.956Z"
|
||||
},
|
||||
"dist-tags": {
|
||||
"beta": "3.0.0",
|
||||
"latest": "3.3.1",
|
||||
"jota": "1.6.3"
|
||||
},
|
||||
"_uplinks": {
|
||||
"npmjs": {
|
||||
"etag": "W/\"252f0a131cedd3ea82dfefd6fa049558\"",
|
||||
"fetched": 1529779934081
|
||||
}
|
||||
},
|
||||
"_distfiles": {
|
||||
"jquery-1.5.1.tgz": {
|
||||
"url": "https://registry.npmjs.org/@jquery%2jquery/-/jquery-1.5.1.tgz",
|
||||
"sha": "2ae2d661e906c1a01e044a71bb5b2743942183e5",
|
||||
"registry": "npmjs"
|
||||
}
|
||||
},
|
||||
"_attachments": {
|
||||
"jquery-1.5.1.tgz": {
|
||||
"shasum": "2ae2d661e906c1a01e044a71bb5b2743942183e5"
|
||||
}
|
||||
},
|
||||
"_rev": "60-fed4915c27b9c1e6",
|
||||
"readme": "# jQuery\n\n> jQuery is a fast, small, and feature-rich JavaScript library.\n\nFor information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/).\nFor source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).\n\nIf upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.\n\n## Including jQuery\n\nBelow are some of the most common ways to include jQuery.\n\n### Browser\n\n#### Script tag\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.3.1.min.js\"></script>\n```\n\n#### Babel\n\n[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.\n\n```js\nimport $ from \"jquery\";\n```\n\n#### Browserify/Webpack\n\nThere are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this...\n\n```js\nvar $ = require(\"jquery\");\n```\n\n#### AMD (Asynchronous Module Definition)\n\nAMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html).\n\n```js\ndefine([\"jquery\"], function($) {\n\n});\n```\n\n### Node\n\nTo include jQuery in [Node](nodejs.org), first install with npm.\n\n```sh\nnpm install jquery\n```\n\nFor jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.\n\n```js\nrequire(\"jsdom\").env(\"\", function(err, window) {\n\tif (err) {\n\t\tconsole.error(err);\n\t\treturn;\n\t}\n\n\tvar $ = require(\"jquery\")(window);\n});\n```"
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "corrupted-package"
|
||||
"version": {},
|
||||
"dist-tags": {},
|
||||
"_distfiles": {},
|
||||
"_attachments": {},
|
||||
"_uplinks": {},
|
||||
"time": {},
|
||||
"_rev": "0-0000000000000000",
|
||||
"readme": "",
|
||||
"versions": {}
|
||||
}
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,75 +0,0 @@
|
||||
{
|
||||
"_id": "npm_test",
|
||||
"name": "npm_test",
|
||||
"description": "",
|
||||
"dist-tags": {
|
||||
"latest": "1.0.0"
|
||||
},
|
||||
"versions": {
|
||||
"1.0.0": {
|
||||
"name": "npm_test",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"test": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "npm_test@1.0.0",
|
||||
"_npmVersion": "5.5.1",
|
||||
"_nodeVersion": "9.3.0",
|
||||
"_npmUser": {},
|
||||
"dist": {
|
||||
"integrity": "sha512-tfzM1OFjWwg2d2Wke/DV6icjeTZUVOZYLkbf8wmONRSAgMovL/F+zyI24OhTtWyOXd1Kbj2YUMBvLpmpAjv8zg==",
|
||||
"shasum": "3e4e6bd5097b295e520b947c9be3259a9509a673",
|
||||
"tarball": "http://localhost:4873/npm_test/-/npm_test-1.0.0.tgz"
|
||||
}
|
||||
},
|
||||
"2.0.0": {
|
||||
"name": "npm_test",
|
||||
"version": "2.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"test": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "npm_test@2.0.0",
|
||||
"_npmVersion": "5.5.1",
|
||||
"_nodeVersion": "9.3.0",
|
||||
"_npmUser": {},
|
||||
"dist": {
|
||||
"integrity": "sha512-tzzM1OFjWwg2d2Wke/DV6icjeTZUVOZYLkbf8wmONRSAgMovL/F+zyI24OhTtWyOXd1Kbj2YUMBvLpmpAjv8zg==",
|
||||
"shasum": "3a4e6bd5097b295e520b947c9be3259a9509a673",
|
||||
"tarball": "http://localhost:4873/npm_test/-/npm_test-2.0.0.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_attachments": {
|
||||
"npm_test-1.0.0.tgz": {
|
||||
"content_type": "application/octet-stream",
|
||||
"data": "H4sIAAAAAAAAE+2ST08CMRDFOe+nmPTAyawt7ELCVT149ihqmu4gI9I2bUGM4bvbbhGM4eYmxmR/l6bvtW+mf6xUK/mMlzaP5Ys3etAxnPNJVcE5PVHV0RPjkairsZiK0YALUU+mMOBdN3KOjQ/SxVZ+m5PPAsfxn/BRADAt18hmwDxpY0k+BfSBXSRni86T0ckUJS95Vhv0ypENByeLa0ntjHSDu/iPvpZajIJWhD66qRwcC6Xlj6KsYm7U94cN2+sfe7KRS34LabuMCaiWBubsxjnjZqANJAO8RUULwmbOYDgE3FEAcSqzwvc345oUd//QKnITlsadzvNKCrVv7+X27ooV++Kv36qnp6enSz4B8bhKUwAIAAA=",
|
||||
"length": 281
|
||||
},
|
||||
"npm_test-2.0.0.tgz": {
|
||||
"content_type": "application/octet-stream",
|
||||
"data": "H4sIAAAAAAAAE+2ST08CMRDFOe+nmPTAyawt7ELCVT149ihqmu4gI9I2bUGM4bvbbhGM4eYmxmR/l6bvtW+mf6xUK/mMlzaP5Ys3etAxnPNJVcE5PVHV0RPjkairsZiK0YALUU+mMOBdN3KOjQ/SxVZ+m5PPAsfxn/BRADAt18hmwDxpY0k+BfSBXSRni86T0ckUJS95Vhv0ypENByeLa0ntjHSDu/iPvpZajIJWhD66qRwcC6Xlj6KsYm7U94cN2+sfe7KRS34LabuMCaiWBubsxjnjZqANJAO8RUULwmbOYDgE3FEAcSqzwvc345oUd//QKnITlsadzvNKCrVv7+X27ooV++Kv36qnp6enSz4B8bhKUwAIAAA=",
|
||||
"length": 281
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
storage: ./storage
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'corrupted-package':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'jquery':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'npm_test':
|
||||
access: $all
|
||||
publish: $all
|
||||
|
||||
log: { type: stdout, format: pretty, level: warn }
|
@ -1,157 +0,0 @@
|
||||
import path from 'path';
|
||||
import request from 'supertest';
|
||||
|
||||
import { DIST_TAGS, HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
|
||||
import { logger, setup } from '@verdaccio/logger';
|
||||
import { DOMAIN_SERVERS, configExample, generateRamdonStorage, mockServer } from '@verdaccio/mock';
|
||||
|
||||
import endPointAPI from '../../src';
|
||||
import forbiddenPlace from './partials/forbidden-place';
|
||||
import publishMetadata from './partials/publish-api';
|
||||
|
||||
setup([]);
|
||||
|
||||
describe('endpoint web unit test', () => {
|
||||
jest.setTimeout(40000);
|
||||
let app;
|
||||
let mockRegistry;
|
||||
|
||||
beforeAll(async () => {
|
||||
const store = generateRamdonStorage();
|
||||
const mockServerPort = 55523;
|
||||
const configForTest = configExample(
|
||||
{
|
||||
storage: store,
|
||||
config_path: store,
|
||||
uplinks: {
|
||||
remote: {
|
||||
url: `http://${DOMAIN_SERVERS}:${mockServerPort}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
'web.yaml',
|
||||
__dirname
|
||||
);
|
||||
app = await endPointAPI(configForTest);
|
||||
const binPath = require.resolve('verdaccio/bin/verdaccio');
|
||||
const storePath = path.join(__dirname, '/mock/store');
|
||||
mockRegistry = await mockServer(mockServerPort, { storePath, silence: true }).init(binPath);
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
const [registry, pid] = mockRegistry;
|
||||
registry.stop();
|
||||
logger.info(`registry ${pid} has been stopped`);
|
||||
});
|
||||
|
||||
describe('Registry WebUI endpoints', () => {
|
||||
beforeAll(async () => {
|
||||
await request(app)
|
||||
.put('/@scope%2fpk1-test')
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.send(JSON.stringify(publishMetadata))
|
||||
.expect(HTTP_STATUS.CREATED);
|
||||
|
||||
await request(app)
|
||||
.put('/forbidden-place')
|
||||
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||
.send(JSON.stringify(forbiddenPlace))
|
||||
.expect(HTTP_STATUS.CREATED);
|
||||
});
|
||||
|
||||
describe('Packages', () => {
|
||||
test('should display sidebar info', () => {
|
||||
return new Promise((resolve) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/data/sidebar/@scope/pk1-test')
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.end(function (err, res) {
|
||||
// console.log("-->", res);
|
||||
// expect(err).toBeNull();
|
||||
|
||||
const sideBarInfo = res.body;
|
||||
const latestVersion = publishMetadata.versions[publishMetadata[DIST_TAGS].latest];
|
||||
|
||||
expect(sideBarInfo.latest.author).toBeDefined();
|
||||
expect(sideBarInfo.latest.author.avatar).toMatch(/www.gravatar.com/);
|
||||
expect(sideBarInfo.latest.author.name).toBe(latestVersion.author.name);
|
||||
expect(sideBarInfo.latest.author.email).toBe(latestVersion.author.email);
|
||||
resolve(sideBarInfo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should display sidebar info by version', () => {
|
||||
return new Promise((resolve) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/data/sidebar/@scope/pk1-test?v=1.0.6')
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.end(function (err, res) {
|
||||
const sideBarInfo = res.body;
|
||||
const latestVersion = publishMetadata.versions[publishMetadata[DIST_TAGS].latest];
|
||||
|
||||
expect(sideBarInfo.latest.author).toBeDefined();
|
||||
expect(sideBarInfo.latest.author.avatar).toMatch(/www.gravatar.com/);
|
||||
expect(sideBarInfo.latest.author.name).toBe(latestVersion.author.name);
|
||||
expect(sideBarInfo.latest.author.email).toBe(latestVersion.author.email);
|
||||
resolve(sideBarInfo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should display sidebar info 404', () => {
|
||||
return new Promise((resolve) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/data/sidebar/@scope/404')
|
||||
.expect(HTTP_STATUS.NOT_FOUND)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.end(function () {
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should display sidebar info 404 with version', () => {
|
||||
return new Promise((resolve) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/data/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 () {
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Search', () => {
|
||||
test('should find @scope/pk1-test', () => {
|
||||
return new Promise((resolve) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/data/search/@scope%2fpk1-test')
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function (_err, res) {
|
||||
expect(res.body).toHaveLength(1);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('should not find forbidden-place', () => {
|
||||
return new Promise((resolve) => {
|
||||
request(app)
|
||||
.get('/-/verdaccio/data/search/forbidden-place')
|
||||
.expect(HTTP_STATUS.OK)
|
||||
.end(function (err, res) {
|
||||
// this is expected since we are not logged
|
||||
// and forbidden-place is allow_access: 'nobody'
|
||||
expect(res.body).toHaveLength(0);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,50 +0,0 @@
|
||||
const json = {
|
||||
_id: 'forbidden-place',
|
||||
name: 'forbidden-place',
|
||||
description: '',
|
||||
'dist-tags': {
|
||||
latest: '1.0.6',
|
||||
},
|
||||
versions: {
|
||||
'1.0.6': {
|
||||
name: 'forbidden-place',
|
||||
version: '1.0.6',
|
||||
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: 'forbidden-place@1.0.6',
|
||||
_npmVersion: '5.5.1',
|
||||
_nodeVersion: '8.7.0',
|
||||
_npmUser: {},
|
||||
dist: {
|
||||
integrity:
|
||||
'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==',
|
||||
shasum: '2c03764f651a9f016ca0b7620421457b619151b9',
|
||||
tarball: 'http://localhost:5555/forbidden-place/-/forbidden-place-1.0.6.tgz',
|
||||
},
|
||||
},
|
||||
},
|
||||
readme: '# test',
|
||||
_attachments: {
|
||||
'forbidden-place-1.0.6.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,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = json;
|
@ -1,50 +0,0 @@
|
||||
const json = {
|
||||
_id: '@scope/pk1-test',
|
||||
name: '@scope/pk1-test',
|
||||
description: '',
|
||||
'dist-tags': {
|
||||
latest: '1.0.6',
|
||||
},
|
||||
versions: {
|
||||
'1.0.6': {
|
||||
name: '@scope/pk1-test',
|
||||
version: '1.0.6',
|
||||
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: '@scope/pk1-test@1.0.6',
|
||||
_npmVersion: '5.5.1',
|
||||
_nodeVersion: '8.7.0',
|
||||
_npmUser: {},
|
||||
dist: {
|
||||
integrity:
|
||||
'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==',
|
||||
shasum: '2c03764f651a9f016ca0b7620421457b619151b9',
|
||||
tarball: 'http://localhost:5555/@scope/pk1-test/-/@scope/pk1-test-1.0.6.tgz',
|
||||
},
|
||||
},
|
||||
},
|
||||
readme: '# test',
|
||||
_attachments: {
|
||||
'@scope/pk1-test-1.0.6.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,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = json;
|
@ -1,20 +0,0 @@
|
||||
storage: ./storage_default_storage
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
unpublish: remote
|
||||
'forbidden-place':
|
||||
access: nobody_can_access_this_package
|
||||
publish: $all
|
||||
'*':
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: xxx
|
||||
proxy: remote
|
||||
log: { type: stdout, format: pretty, level: warn }
|
@ -57,7 +57,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "16.11.47",
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.15",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.12",
|
||||
"@verdaccio/test-helper": "workspace:1.1.0-6-next.1",
|
||||
"undici": "4.16.0",
|
||||
|
@ -1,14 +1,22 @@
|
||||
import { Manifest } from '@verdaccio/types';
|
||||
import buildDebug from 'debug';
|
||||
import path from 'path';
|
||||
|
||||
import { Storage } from '../src/storage';
|
||||
import { parseConfigFile } from '@verdaccio/config';
|
||||
|
||||
export const addPackageToStore = (storage: Storage, pkgName: string, metadata: Manifest) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
storage.addPackage(pkgName, metadata, (err, data) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(data);
|
||||
});
|
||||
});
|
||||
};
|
||||
const debug = buildDebug('verdaccio:mock:config');
|
||||
|
||||
/**
|
||||
* Override the default.yaml configuration file with any new config provided.
|
||||
*/
|
||||
function configExample(externalConfig: any = {}, configFile?: string, location?: string) {
|
||||
let config = {};
|
||||
if (location && configFile) {
|
||||
const locationFile = path.join(location, configFile);
|
||||
debug('config location: %s', locationFile);
|
||||
config = parseConfigFile(locationFile);
|
||||
debug('config file: %o', JSON.stringify(config));
|
||||
}
|
||||
return { ...externalConfig, ...config };
|
||||
}
|
||||
|
||||
export { configExample };
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { setGlobalDispatcher } from 'undici';
|
||||
|
||||
import { Config } from '@verdaccio/config';
|
||||
import { Config, getDefaultConfig } from '@verdaccio/config';
|
||||
import { searchUtils } from '@verdaccio/core';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import { configExample } from '@verdaccio/mock';
|
||||
|
||||
import { Storage, removeDuplicates } from '../src';
|
||||
|
||||
@ -31,7 +30,7 @@ describe('search', () => {
|
||||
test('search items', async () => {
|
||||
const { MockAgent } = require('undici');
|
||||
// FIXME: fetch is already part of undici
|
||||
const domain = 'http://localhost:4873';
|
||||
const domain = 'https://registry.npmjs.org';
|
||||
const url = '/-/v1/search?maintenance=1&popularity=1&quality=1&size=10&text=verdaccio';
|
||||
const response = require('./fixtures/search.json');
|
||||
const options = {
|
||||
@ -43,7 +42,7 @@ describe('search', () => {
|
||||
setGlobalDispatcher(mockAgent);
|
||||
const mockClient = mockAgent.get(domain);
|
||||
mockClient.intercept(options).reply(200, JSON.stringify(response));
|
||||
const config = new Config(configExample());
|
||||
const config = new Config(getDefaultConfig());
|
||||
const storage = new Storage(config);
|
||||
await storage.init(config);
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { pseudoRandomBytes } from 'crypto';
|
||||
import fs from 'fs';
|
||||
import MockDate from 'mockdate';
|
||||
import nock from 'nock';
|
||||
import * as httpMocks from 'node-mocks-http';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { Config } from '@verdaccio/config';
|
||||
import { Config, getDefaultConfig } from '@verdaccio/config';
|
||||
import { API_ERROR, DIST_TAGS, HEADERS, HEADER_TYPE, errorUtils, fileUtils } from '@verdaccio/core';
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import { configExample, generateRamdonStorage } from '@verdaccio/mock';
|
||||
import {
|
||||
addNewVersion,
|
||||
generatePackageMetadata,
|
||||
@ -16,6 +18,14 @@ import { Manifest, Version } from '@verdaccio/types';
|
||||
|
||||
import { Storage } from '../src';
|
||||
import manifestFooRemoteNpmjs from './fixtures/manifests/foo-npmjs.json';
|
||||
import { configExample } from './helpers';
|
||||
|
||||
function generateRamdonStorage() {
|
||||
const tempStorage = pseudoRandomBytes(5).toString('hex');
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), '/verdaccio-test'));
|
||||
|
||||
return path.join(tempRoot, tempStorage);
|
||||
}
|
||||
|
||||
setup({ type: 'stdout', format: 'pretty', level: 'trace' });
|
||||
|
||||
@ -60,6 +70,7 @@ describe('storage', () => {
|
||||
const config = new Config(
|
||||
configExample(
|
||||
{
|
||||
...getDefaultConfig(),
|
||||
storage: generateRamdonStorage(),
|
||||
},
|
||||
'./fixtures/config/updateManifest-1.yaml',
|
||||
@ -264,6 +275,7 @@ describe('storage', () => {
|
||||
test('should not found a package anywhere', (done) => {
|
||||
const config = new Config(
|
||||
configExample({
|
||||
...getDefaultConfig(),
|
||||
storage: generateRamdonStorage(),
|
||||
})
|
||||
);
|
||||
@ -684,6 +696,7 @@ describe('storage', () => {
|
||||
nock(domain).get('/foo').reply(201, fooManifest);
|
||||
const config = new Config(
|
||||
configExample({
|
||||
...getDefaultConfig(),
|
||||
storage: generateRamdonStorage(),
|
||||
})
|
||||
);
|
||||
@ -715,6 +728,7 @@ describe('storage', () => {
|
||||
nock(domain).get('/foo').reply(201, fooManifest);
|
||||
const config = new Config(
|
||||
configExample({
|
||||
...getDefaultConfig(),
|
||||
storage: generateRamdonStorage(),
|
||||
})
|
||||
);
|
||||
@ -747,6 +761,7 @@ describe('storage', () => {
|
||||
nock(domain).get('/foo').reply(201, fooManifest);
|
||||
const config = new Config(
|
||||
configExample({
|
||||
...getDefaultConfig(),
|
||||
storage: generateRamdonStorage(),
|
||||
})
|
||||
);
|
||||
@ -779,6 +794,7 @@ describe('storage', () => {
|
||||
nock(domain).get('/foo').reply(201, fooManifest);
|
||||
const config = new Config(
|
||||
configExample({
|
||||
...getDefaultConfig(),
|
||||
storage: generateRamdonStorage(),
|
||||
})
|
||||
);
|
||||
@ -813,6 +829,12 @@ describe('storage', () => {
|
||||
nock(domain).get('/foo2').reply(404);
|
||||
const config = new Config(
|
||||
configExample({
|
||||
...getDefaultConfig(),
|
||||
uplinks: {
|
||||
npmjs: {
|
||||
url: domain,
|
||||
},
|
||||
},
|
||||
storage: generateRamdonStorage(),
|
||||
})
|
||||
);
|
||||
@ -847,6 +869,12 @@ describe('storage', () => {
|
||||
});
|
||||
const config = new Config(
|
||||
configExample({
|
||||
...getDefaultConfig(),
|
||||
uplinks: {
|
||||
npmjs: {
|
||||
url: domain,
|
||||
},
|
||||
},
|
||||
storage: generateRamdonStorage(),
|
||||
})
|
||||
);
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../../.babelrc"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-console": 0
|
||||
}
|
||||
}
|
@ -1,314 +0,0 @@
|
||||
# @verdaccio/mock
|
||||
|
||||
## 6.0.0-6-next.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d43894e8]
|
||||
- Updated dependencies [d08fe29d]
|
||||
- @verdaccio/config@6.0.0-6-next.14
|
||||
- @verdaccio/core@6.0.0-6-next.5
|
||||
|
||||
## 6.0.0-6-next.14
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 82cb0f2b: feat!: config.logs throw an error, logging config not longer accept array or logs property
|
||||
|
||||
### 💥 Breaking change
|
||||
|
||||
This is valid
|
||||
|
||||
```yaml
|
||||
log: { type: stdout, format: pretty, level: http }
|
||||
```
|
||||
|
||||
This is invalid
|
||||
|
||||
```yaml
|
||||
logs: { type: stdout, format: pretty, level: http }
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```yaml
|
||||
logs:
|
||||
- [{ type: stdout, format: pretty, level: http }]
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [82cb0f2b]
|
||||
- Updated dependencies [5167bb52]
|
||||
- @verdaccio/config@6.0.0-6-next.13
|
||||
- @verdaccio/core@6.0.0-6-next.5
|
||||
- @verdaccio/utils@6.0.0-6-next.11
|
||||
|
||||
## 6.0.0-6-next.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a828271d]
|
||||
- Updated dependencies [24b9be02]
|
||||
- Updated dependencies [b13a3fef]
|
||||
- @verdaccio/utils@6.0.0-6-next.10
|
||||
- @verdaccio/core@6.0.0-6-next.4
|
||||
- @verdaccio/config@6.0.0-6-next.12
|
||||
|
||||
## 6.0.0-6-next.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [f86c31ed]
|
||||
- @verdaccio/utils@6.0.0-6-next.9
|
||||
- @verdaccio/config@6.0.0-6-next.11
|
||||
|
||||
## 6.0.0-6-next.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c1eb021]
|
||||
- @verdaccio/core@6.0.0-6-next.3
|
||||
- @verdaccio/config@6.0.0-6-next.10
|
||||
- @verdaccio/utils@6.0.0-6-next.8
|
||||
|
||||
## 6.0.0-6-next.10
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 794af76c: Remove Node 12 support
|
||||
|
||||
- We need move to the new `undici` and does not support Node.js 12
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 154b2ecd: refactor: remove @verdaccio/commons-api in favor @verdaccio/core and remove duplications
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [794af76c]
|
||||
- Updated dependencies [154b2ecd]
|
||||
- @verdaccio/config@6.0.0-6-next.9
|
||||
- @verdaccio/core@6.0.0-6-next.2
|
||||
- @verdaccio/utils@6.0.0-6-next.7
|
||||
|
||||
## 6.0.0-6-next.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [459b6fa7]
|
||||
- @verdaccio/config@6.0.0-6-next.8
|
||||
- @verdaccio/commons-api@11.0.0-6-next.4
|
||||
- @verdaccio/utils@6.0.0-6-next.6
|
||||
|
||||
## 6.0.0-6-next.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- df0da3d6: Added core-js missing from dependencies though referenced in .js sources
|
||||
|
||||
## 6.0.0-6-next.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d2c65da9]
|
||||
- @verdaccio/utils@6.0.0-6-next.5
|
||||
- @verdaccio/config@6.0.0-6-next.7
|
||||
|
||||
## 6.0.0-6-next.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1b217fd3]
|
||||
- @verdaccio/config@6.0.0-6-next.6
|
||||
|
||||
## 6.0.0-6-next.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 648575aa: Bug Fixes
|
||||
|
||||
- fix escaped slash in namespaced packages
|
||||
|
||||
#### Related tickets
|
||||
|
||||
https://github.com/verdaccio/verdaccio/pull/2193
|
||||
|
||||
- Updated dependencies [1810ed0d]
|
||||
- Updated dependencies [648575aa]
|
||||
- @verdaccio/config@6.0.0-6-next.5
|
||||
- @verdaccio/utils@6.0.0-6-next.4
|
||||
|
||||
## 6.0.0-6-next.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5c5057fc]
|
||||
- @verdaccio/config@6.0.0-6-next.4
|
||||
|
||||
## 5.0.0-alpha.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fecbb9be: chore: add release step to private regisry on merge changeset pr
|
||||
- Updated dependencies [fecbb9be]
|
||||
- @verdaccio/config@5.0.0-alpha.3
|
||||
- @verdaccio/commons-api@10.0.0-alpha.3
|
||||
- @verdaccio/utils@5.0.0-alpha.3
|
||||
|
||||
## 5.0.0-alpha.2
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 54c58d1e: feat: add server rate limit protection to all request
|
||||
|
||||
To modify custom values, use the server settings property.
|
||||
|
||||
```markdown
|
||||
server:
|
||||
|
||||
## https://www.npmjs.com/package/express-rate-limit#configuration-options
|
||||
|
||||
rateLimit:
|
||||
windowMs: 1000
|
||||
max: 10000
|
||||
```
|
||||
|
||||
The values are intended to be high, if you want to improve security of your server consider
|
||||
using different values.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [54c58d1e]
|
||||
- @verdaccio/config@5.0.0-alpha.2
|
||||
- @verdaccio/commons-api@10.0.0-alpha.2
|
||||
- @verdaccio/utils@5.0.0-alpha.2
|
||||
|
||||
## 5.0.0-alpha.1
|
||||
|
||||
### Major Changes
|
||||
|
||||
- d87fa026: feat!: experiments config renamed to flags
|
||||
|
||||
- The `experiments` configuration is renamed to `flags`. The functionality is exactly the same.
|
||||
|
||||
```js
|
||||
flags: token: false;
|
||||
search: false;
|
||||
```
|
||||
|
||||
- The `self_path` property from the config file is being removed in favor of `config_file` full path.
|
||||
- Refactor `config` module, better types and utilities
|
||||
|
||||
- da1ee9c8: - Replace signature handler for legacy tokens by removing deprecated crypto.createDecipher by createCipheriv
|
||||
|
||||
- Introduce environment variables for legacy tokens
|
||||
|
||||
### Code Improvements
|
||||
|
||||
- Add debug library for improve developer experience
|
||||
|
||||
### Breaking change
|
||||
|
||||
- The new signature invalidates all previous tokens generated by Verdaccio 4 or previous versions.
|
||||
- The secret key must have 32 characters long.
|
||||
|
||||
### New environment variables
|
||||
|
||||
- `VERDACCIO_LEGACY_ALGORITHM`: Allows to define the specific algorithm for the token signature which by default is `aes-256-ctr`
|
||||
- `VERDACCIO_LEGACY_ENCRYPTION_KEY`: By default, the token stores in the database, but using this variable allows to get it from memory
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 26b494cb: feat: add typescript project references settings
|
||||
|
||||
Reading https://ebaytech.berlin/optimizing-multi-package-apps-with-typescript-project-references-d5c57a3b4440 I realized I can use project references to solve the issue to pre-compile modules on develop mode.
|
||||
|
||||
It allows to navigate (IDE) trough the packages without need compile the packages.
|
||||
|
||||
Add two `tsconfig`, one using the previous existing configuration that is able to produce declaration files (`tsconfig.build`) and a new one `tsconfig` which is enables [_projects references_](https://www.typescriptlang.org/docs/handbook/project-references.html).
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b57b4338: Enable prerelease mode with **changesets**
|
||||
- 31af0164: ESLint Warnings Fixed
|
||||
|
||||
Related to issue #1461
|
||||
|
||||
- max-len: most of the sensible max-len errors are fixed
|
||||
- no-unused-vars: most of these types of errors are fixed by deleting not needed declarations
|
||||
- @typescript-eslint/no-unused-vars: same as above
|
||||
|
||||
- Updated dependencies [d87fa026]
|
||||
- Updated dependencies [da1ee9c8]
|
||||
- Updated dependencies [26b494cb]
|
||||
- Updated dependencies [b57b4338]
|
||||
- Updated dependencies [31af0164]
|
||||
- @verdaccio/config@5.0.0-alpha.1
|
||||
- @verdaccio/commons-api@10.0.0-alpha.1
|
||||
- @verdaccio/utils@5.0.0-alpha.1
|
||||
|
||||
## 5.0.0-alpha.1
|
||||
|
||||
### Major Changes
|
||||
|
||||
- d87fa0268: feat!: experiments config renamed to flags
|
||||
|
||||
- The `experiments` configuration is renamed to `flags`. The functionality is exactly the same.
|
||||
|
||||
```js
|
||||
flags: token: false;
|
||||
search: false;
|
||||
```
|
||||
|
||||
- The `self_path` property from the config file is being removed in favor of `config_file` full path.
|
||||
- Refactor `config` module, better types and utilities
|
||||
|
||||
- da1ee9c82: - Replace signature handler for legacy tokens by removing deprecated crypto.createDecipher by createCipheriv
|
||||
|
||||
- Introduce environment variables for legacy tokens
|
||||
|
||||
### Code Improvements
|
||||
|
||||
- Add debug library for improve developer experience
|
||||
|
||||
### Breaking change
|
||||
|
||||
- The new signature invalidates all previous tokens generated by Verdaccio 4 or previous versions.
|
||||
- The secret key must have 32 characters long.
|
||||
|
||||
### New environment variables
|
||||
|
||||
- `VERDACCIO_LEGACY_ALGORITHM`: Allows to define the specific algorithm for the token signature which by default is `aes-256-ctr`
|
||||
- `VERDACCIO_LEGACY_ENCRYPTION_KEY`: By default, the token stores in the database, but using this variable allows to get it from memory
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 26b494cbd: feat: add typescript project references settings
|
||||
|
||||
Reading https://ebaytech.berlin/optimizing-multi-package-apps-with-typescript-project-references-d5c57a3b4440 I realized I can use project references to solve the issue to pre-compile modules on develop mode.
|
||||
|
||||
It allows to navigate (IDE) trough the packages without need compile the packages.
|
||||
|
||||
Add two `tsconfig`, one using the previous existing configuration that is able to produce declaration files (`tsconfig.build`) and a new one `tsconfig` which is enables [_projects references_](https://www.typescriptlang.org/docs/handbook/project-references.html).
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b57b43388: Enable prerelease mode with **changesets**
|
||||
- 31af01641: ESLint Warnings Fixed
|
||||
|
||||
Related to issue #1461
|
||||
|
||||
- max-len: most of the sensible max-len errors are fixed
|
||||
- no-unused-vars: most of these types of errors are fixed by deleting not needed declarations
|
||||
- @typescript-eslint/no-unused-vars: same as above
|
||||
|
||||
- Updated dependencies [d87fa0268]
|
||||
- Updated dependencies [da1ee9c82]
|
||||
- Updated dependencies [26b494cbd]
|
||||
- Updated dependencies [b57b43388]
|
||||
- Updated dependencies [31af01641]
|
||||
- @verdaccio/config@5.0.0-alpha.1
|
||||
- @verdaccio/commons-api@10.0.0-alpha.0
|
||||
- @verdaccio/utils@5.0.0-alpha.1
|
||||
- verdaccio@5.0.0-alpha.1
|
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Verdaccio community
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,75 +0,0 @@
|
||||
# @verdaccio/mock
|
||||
|
||||
[](https://opencollective.com/verdaccio)
|
||||
[](https://stackshare.io/verdaccio)
|
||||
[](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)
|
||||
[](https://crowdin.com/project/verdaccio)
|
||||
[](https://www.tickgit.com/browse?repo=github.com/verdaccio/verdaccio)
|
||||
|
||||
[](https://twitter.com/verdaccio_npm)
|
||||
[](https://github.com/verdaccio/verdaccio/stargazers)
|
||||
|
||||
## Donations
|
||||
|
||||
Verdaccio is run by **volunteers**; nobody is working full-time on it. If you find this project to be useful and would like to support its development, consider making a donation - **your logo might end up in this readme.** 😉
|
||||
|
||||
**[Donate](https://opencollective.com/verdaccio)** 💵👍🏻 starting from _\$1/month_ or just one single contribution.
|
||||
|
||||
## Report a vulnerability
|
||||
|
||||
If you want to report a security vulnerability, please follow the steps which we have defined for you in our [security policy](https://github.com/verdaccio/verdaccio/security/policy).
|
||||
|
||||
## Open Collective Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/verdaccio#sponsor)]
|
||||
|
||||
[](https://opencollective.com/verdaccio/sponsor/0/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/1/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/2/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/3/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/4/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/5/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/6/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/7/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/8/website)
|
||||
[](https://opencollective.com/verdaccio/sponsor/9/website)
|
||||
|
||||
## Open Collective Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/verdaccio#backer)]
|
||||
|
||||
[](https://opencollective.com/verdaccio#backers)
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Thanks to the following companies to help us to achieve our goals providing free open source licenses.
|
||||
|
||||
[](https://www.jetbrains.com/)
|
||||
[](https://crowdin.com/)
|
||||
[](https://balsamiq.com/)
|
||||
|
||||
## Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
|
||||
[](../../graphs/contributors)
|
||||
|
||||
### FAQ / Contact / Troubleshoot
|
||||
|
||||
If you have any issue you can try the following options, do no desist to ask or check our issues database, perhaps someone has asked already what you are looking for.
|
||||
|
||||
- [Blog](https://verdaccio.org/blog/)
|
||||
- [Donations](https://opencollective.com/verdaccio)
|
||||
- [Reporting an issue](https://github.com/verdaccio/verdaccio/blob/master/CONTRIBUTING.md#reporting-a-bug)
|
||||
- [Running discussions](https://github.com/verdaccio/verdaccio/issues?q=is%3Aissue+is%3Aopen+label%3Adiscuss)
|
||||
- [Chat](http://chat.verdaccio.org/)
|
||||
- [Logos](https://verdaccio.org/docs/en/logo)
|
||||
- [Docker Examples](https://github.com/verdaccio/docker-examples)
|
||||
- [FAQ](https://github.com/verdaccio/verdaccio/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Aquestion%20)
|
||||
|
||||
### License
|
||||
|
||||
Verdaccio is [MIT licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)
|
||||
|
||||
The Verdaccio documentation and logos (excluding /thanks, e.g., .md, .png, .sketch) files within the /assets folder) is
|
||||
[Creative Commons licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE-docs).
|
@ -1,10 +0,0 @@
|
||||
const config = require('../../../jest/config');
|
||||
|
||||
module.exports = Object.assign({}, config, {
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
// FIXME: increase to 90
|
||||
lines: 40,
|
||||
},
|
||||
},
|
||||
});
|
@ -1,61 +0,0 @@
|
||||
{
|
||||
"name": "@verdaccio/mock",
|
||||
"version": "6.0.0-6-next.15",
|
||||
"private": true,
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "https",
|
||||
"url": "https://github.com/verdaccio/verdaccio"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://verdaccio.org",
|
||||
"keywords": [
|
||||
"private",
|
||||
"package",
|
||||
"repository",
|
||||
"registry",
|
||||
"enterprise",
|
||||
"modules",
|
||||
"proxy",
|
||||
"server",
|
||||
"verdaccio"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"description": "mock server for testing",
|
||||
"main": "./build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
"scripts": {
|
||||
"clean": "rimraf ./build",
|
||||
"test": "echo 0",
|
||||
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
||||
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
|
||||
"watch": "pnpm build:js -- --watch",
|
||||
"build": "pnpm run build:js && pnpm run build:types"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.5",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.14",
|
||||
"@verdaccio/utils": "workspace:6.0.0-6-next.11",
|
||||
"core-js": "3.24.1",
|
||||
"debug": "4.3.4",
|
||||
"fs-extra": "10.1.0",
|
||||
"lodash": "4.17.21",
|
||||
"request": "2.88.2",
|
||||
"supertest": "6.2.4",
|
||||
"verdaccio": "5.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.12"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/verdaccio"
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import buildDebug from 'debug';
|
||||
import _ from 'lodash';
|
||||
import path from 'path';
|
||||
|
||||
import { parseConfigFile } from '@verdaccio/config';
|
||||
import { ConfigYaml } from '@verdaccio/types';
|
||||
|
||||
const debug = buildDebug('verdaccio:mock:config');
|
||||
|
||||
/**
|
||||
* Override the default.yaml configuration file with any new config provided.
|
||||
*/
|
||||
function configExample(
|
||||
externalConfig: Partial<ConfigYaml> = {},
|
||||
configFile: string = 'default.yaml',
|
||||
location: string = ''
|
||||
) {
|
||||
const locationFile = location
|
||||
? path.join(location, configFile)
|
||||
: path.join(__dirname, `./config/yaml/${configFile}`);
|
||||
debug('config location: %s', locationFile);
|
||||
const config = parseConfigFile(locationFile);
|
||||
debug('config file: %o', JSON.stringify(config));
|
||||
return _.assign({}, _.cloneDeep(config), externalConfig);
|
||||
}
|
||||
|
||||
export { configExample };
|
@ -1,37 +0,0 @@
|
||||
storage: ./storage_default_storage
|
||||
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: http://localhost:4873/
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'forbidden-place':
|
||||
access: nobody
|
||||
publish: $all
|
||||
'react':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'corrupted-package':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'jquery':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'auth-package':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
'vue':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
proxy: npmjs
|
||||
'*':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
log: { type: stdout, format: pretty, level: warn }
|
@ -1,26 +0,0 @@
|
||||
storage: ./mock-store
|
||||
|
||||
web:
|
||||
enable: false
|
||||
title: verdaccio-server-unit-test
|
||||
|
||||
auth:
|
||||
auth-memory:
|
||||
users:
|
||||
test:
|
||||
name: test
|
||||
password: test
|
||||
|
||||
log: { type: stdout, format: pretty, level: warn }
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: none
|
||||
unpublish: none
|
||||
'**':
|
||||
access: $all
|
||||
publish: none
|
||||
unpublish: none
|
||||
|
||||
_debug: true
|
@ -1,11 +0,0 @@
|
||||
export const DOMAIN_SERVERS = 'localhost';
|
||||
export const CREDENTIALS = {
|
||||
user: 'test',
|
||||
password: 'test',
|
||||
};
|
||||
|
||||
export const TARBALL = 'tarball-blahblah-file.name';
|
||||
export const PORT_SERVER_APP = '55550';
|
||||
export const PORT_SERVER_1 = '55551';
|
||||
export const PORT_SERVER_2 = '55552';
|
||||
export const PORT_SERVER_3 = '55553';
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@
|
||||
import { DOMAIN_SERVERS, PORT_SERVER_1, TARBALL } from '../constants';
|
||||
|
||||
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}`,
|
||||
},
|
||||
};
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
export * from './constants';
|
||||
export * from './server_process';
|
||||
export * from './request';
|
||||
export * from './utils-test';
|
||||
export * from './verdaccio-server';
|
||||
export * from './fixtures/package';
|
||||
export * from './server';
|
||||
export * from './config';
|
||||
export * from './mock';
|
||||
export * from './mock-api';
|
||||
export * from './types';
|
@ -1,234 +0,0 @@
|
||||
import buildDebug from 'debug';
|
||||
import _ from 'lodash';
|
||||
import request from 'supertest';
|
||||
|
||||
import {
|
||||
DIST_TAGS,
|
||||
HEADERS,
|
||||
HEADER_TYPE,
|
||||
HTTP_STATUS,
|
||||
LATEST,
|
||||
TOKEN_BEARER,
|
||||
} from '@verdaccio/core';
|
||||
import { Package } from '@verdaccio/types';
|
||||
import { buildToken } from '@verdaccio/utils';
|
||||
import { generateRandomHexString } from '@verdaccio/utils';
|
||||
|
||||
const debug = buildDebug('verdaccio:mock:api');
|
||||
|
||||
// API Helpers
|
||||
|
||||
// This file should contain utilities to avoid repeated task over API unit testing,
|
||||
// Please, comply with the following:
|
||||
// - Promisify everything
|
||||
// - Encourage using constants or create new ones if it's needed
|
||||
// - // @ts-ignore or any is fine if there is no other way
|
||||
|
||||
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);
|
||||
|
||||
// the version must exist
|
||||
const latestPkg = pkg.versions[taggedVersion];
|
||||
expect(latestPkg).toBeDefined();
|
||||
// the name must match
|
||||
expect(latestPkg.name).toEqual(pkgName);
|
||||
|
||||
return latestPkg;
|
||||
}
|
||||
|
||||
export function putPackage(
|
||||
request: any,
|
||||
pkgName: string,
|
||||
publishMetadata: Package,
|
||||
token?: string
|
||||
): Promise<any[]> {
|
||||
return new Promise((resolve) => {
|
||||
const 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<any[]> {
|
||||
return new Promise((resolve) => {
|
||||
const del = request
|
||||
.put(`/${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]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getPackage(
|
||||
request: any,
|
||||
token: string,
|
||||
pkgName: string,
|
||||
statusCode: number = HTTP_STATUS.OK
|
||||
): Promise<any[]> {
|
||||
return new Promise((resolve) => {
|
||||
const getRequest = request.get(`/${pkgName}`);
|
||||
|
||||
if (_.isNil(token) === false || _.isEmpty(token) === false) {
|
||||
getRequest.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token));
|
||||
}
|
||||
|
||||
getRequest
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(statusCode)
|
||||
.end(function (err, res) {
|
||||
resolve([err, res]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function loginUserToken(
|
||||
request: any,
|
||||
user: string,
|
||||
credentials: any,
|
||||
token: string,
|
||||
statusCode: number = HTTP_STATUS.CREATED
|
||||
): Promise<any[]> {
|
||||
return new Promise((resolve) => {
|
||||
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) {
|
||||
return resolve([err, res]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function addUser(
|
||||
request: any,
|
||||
user: string,
|
||||
credentials: any,
|
||||
statusCode: number = HTTP_STATUS.CREATED
|
||||
): Promise<any[]> {
|
||||
return new Promise((resolve) => {
|
||||
debug('add user %o %o', user, credentials);
|
||||
request
|
||||
.put(`/-/user/org.couchdb.user:${user}`)
|
||||
.send(credentials)
|
||||
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
||||
.expect(statusCode)
|
||||
.end(function (err, res) {
|
||||
debug('user added error %o - res %o', err?.message, res.body);
|
||||
return resolve([err, res]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function getNewToken(request: any, credentials: any): Promise<string> {
|
||||
/* eslint no-async-promise-executor: 0 */
|
||||
return new Promise(async (resolve) => {
|
||||
const [err, res] = await addUser(request, credentials.name, credentials);
|
||||
expect(err).toBeNull();
|
||||
const { token, ok } = res.body;
|
||||
expect(ok).toBeDefined();
|
||||
expect(token).toBeDefined();
|
||||
expect(typeof token).toBe('string');
|
||||
resolve(token);
|
||||
});
|
||||
}
|
||||
|
||||
export function getProfile(
|
||||
request: any,
|
||||
token: string,
|
||||
statusCode: number = HTTP_STATUS.OK
|
||||
): Promise<any[]> {
|
||||
// $FlowFixMe
|
||||
return new Promise((resolve) => {
|
||||
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) {
|
||||
return resolve([err, res]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function postProfile(
|
||||
request: any,
|
||||
body: any,
|
||||
token: string,
|
||||
statusCode: number = HTTP_STATUS.OK
|
||||
): Promise<any[]> {
|
||||
// $FlowFixMe
|
||||
return new Promise((resolve) => {
|
||||
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) {
|
||||
return resolve([err, res]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchPackageByVersionAndTag(
|
||||
app,
|
||||
encodedPkgName,
|
||||
pkgName,
|
||||
version,
|
||||
tag = 'latest'
|
||||
) {
|
||||
// we retrieve the package to verify
|
||||
const [err, resp] = await getPackage(request(app), '', encodedPkgName);
|
||||
|
||||
expect(err).toBeNull();
|
||||
|
||||
// we check whether the latest version match with the previous published one
|
||||
return getTaggedVersionFromPackage(resp.body, pkgName, tag, version);
|
||||
}
|
||||
|
||||
export async function isExistPackage(app, packageName) {
|
||||
const [err] = await getPackage(request(app), '', 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, packageName, HTTP_STATUS.OK);
|
||||
|
||||
const { versions } = res.body;
|
||||
const versionsKeys = Object.keys(versions);
|
||||
|
||||
return versionsKeys.includes(version) === false;
|
||||
}
|
||||
|
||||
export function generateUnPublishURI(pkgName) {
|
||||
return `/${pkgName}/-rev/${generateRandomHexString(8)}`;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import * as fsExtra from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { DOMAIN_SERVERS } from './constants';
|
||||
import Server, { IServerBridge } from './server';
|
||||
import VerdaccioProcess from './server_process';
|
||||
import { VerdaccioConfig } from './verdaccio-server';
|
||||
|
||||
/**
|
||||
* Fork a Verdaccio process with a custom configuration.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* - Fork the process within the beforeAll body.
|
||||
* - Define a storage (use a specific name)
|
||||
* - Define a unique port (be careful with conflicts)
|
||||
* - Set a configuration
|
||||
* - await / mockServer
|
||||
* - call done();
|
||||
*
|
||||
* beforeAll(function(done) {
|
||||
const store = path.join(__dirname, '../partials/store/test-profile-storage');
|
||||
const mockServerPort = 55544;
|
||||
rimraf(store, async () => {
|
||||
const parsedConfig = parseConfigFile(parseConfigurationProfile());
|
||||
const configForTest = _.assign({}, _.cloneDeep(parsedConfig), {
|
||||
storage: store,
|
||||
auth: {
|
||||
htpasswd: {
|
||||
file: './test-profile-storage/.htpasswd'
|
||||
}
|
||||
},
|
||||
config_path: store
|
||||
});
|
||||
app = await endPointAPI(configForTest);
|
||||
mockRegistry = await mockServer(mockServerPort).init();
|
||||
done();
|
||||
});
|
||||
|
||||
On finish the test we must close the server
|
||||
|
||||
afterAll(function(done) {
|
||||
mockRegistry[0].stop();
|
||||
done();
|
||||
});
|
||||
|
||||
*
|
||||
*
|
||||
* @param port
|
||||
* @returns {VerdaccioProcess}
|
||||
*/
|
||||
export function mockServer(port: number, options: MockRegistryOptions = {}) {
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), '/verdaccio-test'));
|
||||
|
||||
// default locations
|
||||
const configPath = path.join(__dirname, './config/yaml', '/mock-server-test.yaml');
|
||||
const mockStorePath = path.join(__dirname, '/fixtures/mock-store');
|
||||
|
||||
// default options
|
||||
const localOptions: MockRegistryOptions = {
|
||||
port,
|
||||
configPath,
|
||||
storePath: mockStorePath,
|
||||
rootFolder: tempRoot,
|
||||
silence: true,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
// mix external options
|
||||
const finalOptions: MockRegistryOptions = Object.assign({}, localOptions, options);
|
||||
// final locations
|
||||
const tempConfigFile = path.join(tempRoot, 'verdaccio.yaml');
|
||||
const storePath = path.join(tempRoot, '/mock-store');
|
||||
|
||||
fs.copyFileSync(finalOptions.configPath!, tempConfigFile);
|
||||
fsExtra.copySync(finalOptions.storePath!, storePath);
|
||||
|
||||
const verdaccioConfig = new VerdaccioConfig(
|
||||
storePath,
|
||||
tempConfigFile,
|
||||
`http://${DOMAIN_SERVERS}:${port}/`,
|
||||
port
|
||||
);
|
||||
const server: IServerBridge = new Server(verdaccioConfig.domainPath);
|
||||
|
||||
return new VerdaccioProcess(verdaccioConfig, server, finalOptions.silence, finalOptions.debug);
|
||||
}
|
||||
|
||||
export interface MockRegistryOptions {
|
||||
rootFolder?: string;
|
||||
configPath?: string;
|
||||
port?: number;
|
||||
storePath?: string;
|
||||
silence?: boolean;
|
||||
debug?: boolean;
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
import assert from 'assert';
|
||||
import buildDebug from 'debug';
|
||||
import _ from 'lodash';
|
||||
import request from 'request';
|
||||
|
||||
import { IRequestPromise } from './server';
|
||||
|
||||
const requestData = Symbol('smart_request_data');
|
||||
|
||||
const debug = buildDebug('verdaccio:mock:request');
|
||||
|
||||
export class PromiseAssert extends Promise<any> implements IRequestPromise {
|
||||
public constructor(options: any) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
public status(expected: number) {
|
||||
const selfData = this[requestData];
|
||||
|
||||
return injectResponse(
|
||||
this,
|
||||
this.then(function (body) {
|
||||
try {
|
||||
assert.equal(selfData.response.statusCode, expected);
|
||||
} catch (err: any) {
|
||||
debug('error status %o', 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 {
|
||||
debug('body_ok %o', body);
|
||||
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: any) {
|
||||
debug('body_ok error %o', err.message);
|
||||
selfData.error.message = err.message;
|
||||
throw selfData.error;
|
||||
}
|
||||
|
||||
return body;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public body_error(expected: any) {
|
||||
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);
|
||||
}
|
||||
assert.equal(body.ok, null);
|
||||
} catch (err: any) {
|
||||
selfData.error.message = err.message;
|
||||
throw selfData.error;
|
||||
}
|
||||
return body;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public request(callback: any) {
|
||||
callback(this[requestData].request);
|
||||
return this;
|
||||
}
|
||||
|
||||
public response(cb: any) {
|
||||
const selfData = this[requestData];
|
||||
|
||||
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<any>): Promise<any> {
|
||||
promise[requestData] = smartObject[requestData];
|
||||
return promise;
|
||||
}
|
||||
|
||||
function smartRequest(options: any): Promise<any> {
|
||||
const smartObject: any = {};
|
||||
|
||||
smartObject[requestData] = {};
|
||||
smartObject[requestData].error = Error();
|
||||
Error.captureStackTrace(smartObject[requestData].error, smartRequest);
|
||||
|
||||
const promiseResult: Promise<any> = new PromiseAssert(function (resolve, reject) {
|
||||
// store request reference on symbol
|
||||
smartObject[requestData].request = request(options, function (err, res, body) {
|
||||
if (err) {
|
||||
debug('error request %o', err);
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
// store the response on symbol
|
||||
smartObject[requestData].response = res;
|
||||
resolve(body);
|
||||
});
|
||||
});
|
||||
|
||||
return injectResponse(smartObject, promiseResult);
|
||||
}
|
||||
|
||||
export default smartRequest;
|
@ -1,271 +0,0 @@
|
||||
import assert from 'assert';
|
||||
import buildDebug from 'debug';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { API_MESSAGE, HEADERS, HTTP_STATUS, TOKEN_BASIC } from '@verdaccio/core';
|
||||
import { buildToken } from '@verdaccio/utils';
|
||||
|
||||
import { CREDENTIALS } from './constants';
|
||||
import getPackage from './fixtures/package';
|
||||
import smartRequest, { PromiseAssert } from './request';
|
||||
|
||||
const buildAuthHeader = (user, pass): string => {
|
||||
return buildToken(TOKEN_BASIC, Buffer.from(`${user}:${pass}`).toString('base64'));
|
||||
};
|
||||
|
||||
const debug = buildDebug('verdaccio:mock:server');
|
||||
|
||||
export interface IRequestPromise {
|
||||
status(reason: any): any;
|
||||
body_ok(reason: any): any;
|
||||
body_error(reason: any): any;
|
||||
request(reason: any): any;
|
||||
response(reason: any): any;
|
||||
send(reason: any): any;
|
||||
}
|
||||
|
||||
export interface IServerBridge {
|
||||
url: string;
|
||||
userAgent: string;
|
||||
authstr: string;
|
||||
request(options: any): typeof PromiseAssert;
|
||||
auth(name: string, password: string): IRequestPromise;
|
||||
auth(name: string, password: string): IRequestPromise;
|
||||
logout(token: string): Promise<any>;
|
||||
getPackage(name: string): Promise<any>;
|
||||
putPackage(name: string, data: any): Promise<any>;
|
||||
putVersion(name: string, version: string, data: any): Promise<any>;
|
||||
getTarball(name: string, filename: string): Promise<any>;
|
||||
putTarball(name: string, filename: string, data: any): Promise<any>;
|
||||
removeTarball(name: string): Promise<any>;
|
||||
removeSingleTarball(name: string, filename: string): Promise<any>;
|
||||
addTag(name: string, tag: string, version: string): Promise<any>;
|
||||
putTarballIncomplete(
|
||||
name: string,
|
||||
filename: string,
|
||||
data: any,
|
||||
size: number,
|
||||
cb: Function
|
||||
): Promise<any>;
|
||||
addPackage(name: string): Promise<any>;
|
||||
whoami(): Promise<any>;
|
||||
ping(): Promise<any>;
|
||||
debug(): IRequestPromise;
|
||||
}
|
||||
|
||||
export default class Server implements IServerBridge {
|
||||
public url: string;
|
||||
public userAgent: string;
|
||||
public authstr: string;
|
||||
|
||||
public constructor(url: string) {
|
||||
this.url = url.replace(/\/$/, '');
|
||||
this.userAgent = 'node/v8.1.2 linux x64';
|
||||
this.authstr = buildAuthHeader(CREDENTIALS.user, CREDENTIALS.password);
|
||||
}
|
||||
|
||||
public request(options: any): any {
|
||||
debug('request to %o', options.uri);
|
||||
assert(options.uri);
|
||||
const headers = options.headers || {};
|
||||
|
||||
headers.accept = headers.accept || HEADERS.JSON;
|
||||
headers['user-agent'] = headers['user-agent'] || this.userAgent;
|
||||
headers.authorization = headers.authorization || this.authstr;
|
||||
debug('request headers %o', headers);
|
||||
|
||||
return smartRequest({
|
||||
url: this.url + options.uri,
|
||||
method: options.method || 'GET',
|
||||
headers: headers,
|
||||
encoding: options.encoding,
|
||||
json: _.isNil(options.json) === false ? options.json : true,
|
||||
});
|
||||
}
|
||||
|
||||
public auth(name: string, password: string) {
|
||||
debug('request auth %o:%o', name, password);
|
||||
this.authstr = buildAuthHeader(name, password);
|
||||
return this.request({
|
||||
uri: `/-/user/org.couchdb.user:${encodeURIComponent(name)}/-rev/undefined`,
|
||||
method: 'PUT',
|
||||
json: {
|
||||
name,
|
||||
password,
|
||||
email: `${CREDENTIALS.user}@example.com`,
|
||||
_id: `org.couchdb.user:${name}`,
|
||||
type: 'user',
|
||||
roles: [],
|
||||
date: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public logout(token: string) {
|
||||
return this.request({
|
||||
uri: `/-/user/token/${encodeURIComponent(token)}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
public getPackage(name: string) {
|
||||
return this.request({
|
||||
uri: `/${encodeURIComponent(name)}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
public putPackage(name: string, data) {
|
||||
if (_.isObject(data) && !Buffer.isBuffer(data)) {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
|
||||
return this.request({
|
||||
uri: `/${encodeURIComponent(name)}`,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
[HEADERS.CONTENT_TYPE]: HEADERS.JSON,
|
||||
},
|
||||
}).send(data);
|
||||
}
|
||||
|
||||
public putVersion(name: string, version: string, data: any) {
|
||||
if (_.isObject(data) && !Buffer.isBuffer(data)) {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
|
||||
return this.request({
|
||||
uri: `/${encodeURIComponent(name)}/${encodeURIComponent(version)}/-tag/latest`,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
[HEADERS.CONTENT_TYPE]: HEADERS.JSON,
|
||||
},
|
||||
}).send(data);
|
||||
}
|
||||
|
||||
public getTarball(name: string, filename: string) {
|
||||
return this.request({
|
||||
uri: `/${encodeURIComponent(name)}/-/${encodeURIComponent(filename)}`,
|
||||
method: 'GET',
|
||||
encoding: null,
|
||||
});
|
||||
}
|
||||
|
||||
public putTarball(name: string, filename: string, data: any) {
|
||||
return this.request({
|
||||
uri: `/${encodeURIComponent(name)}/-/${encodeURIComponent(filename)}/whatever`,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
[HEADERS.CONTENT_TYPE]: HEADERS.OCTET_STREAM,
|
||||
},
|
||||
}).send(data);
|
||||
}
|
||||
|
||||
public removeTarball(name: string) {
|
||||
return this.request({
|
||||
uri: `/${encodeURIComponent(name)}/-rev/whatever`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
[HEADERS.CONTENT_TYPE]: HEADERS.JSON_CHARSET,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public removeSingleTarball(name: string, filename: string) {
|
||||
return this.request({
|
||||
uri: `/${encodeURIComponent(name)}/-/${filename}/-rev/whatever`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
[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,
|
||||
},
|
||||
}).send(JSON.stringify(version));
|
||||
}
|
||||
|
||||
public putTarballIncomplete(
|
||||
pkgName: string,
|
||||
filename: string,
|
||||
data: any,
|
||||
headerContentSize: number
|
||||
): Promise<any> {
|
||||
const promise = this.request({
|
||||
uri: `/${encodeURIComponent(pkgName)}/-/${encodeURIComponent(filename)}/whatever`,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
[HEADERS.CONTENT_TYPE]: HEADERS.OCTET_STREAM,
|
||||
[HEADERS.CONTENT_LENGTH]: headerContentSize,
|
||||
},
|
||||
timeout: 1000,
|
||||
});
|
||||
|
||||
promise.request(function (req) {
|
||||
req.write(data);
|
||||
// it auto abort the request
|
||||
setTimeout(function () {
|
||||
req.req.abort();
|
||||
}, 20);
|
||||
});
|
||||
|
||||
return new Promise<void>(function (resolve, reject) {
|
||||
promise
|
||||
.then(function () {
|
||||
reject(Error('no error'));
|
||||
})
|
||||
.catch(function (err) {
|
||||
if (err.code === 'ECONNRESET') {
|
||||
// @ts-ignore
|
||||
resolve();
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public addPackage(name: string) {
|
||||
return this.putPackage(name, getPackage(name))
|
||||
.status(HTTP_STATUS.CREATED)
|
||||
.body_ok(API_MESSAGE.PKG_CREATED);
|
||||
}
|
||||
|
||||
public whoami() {
|
||||
debug('request whoami');
|
||||
return this.request({
|
||||
uri: '/-/whoami',
|
||||
})
|
||||
.status(HTTP_STATUS.OK)
|
||||
.then(function (body) {
|
||||
debug('request whoami body %o', body);
|
||||
return body.username;
|
||||
});
|
||||
}
|
||||
|
||||
public ping() {
|
||||
return this.request({
|
||||
uri: '/-/ping',
|
||||
})
|
||||
.status(HTTP_STATUS.OK)
|
||||
.then(function (body) {
|
||||
return body;
|
||||
});
|
||||
}
|
||||
|
||||
public debug() {
|
||||
return this.request({
|
||||
uri: '/-/_debug',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
[HEADERS.CONTENT_TYPE]: HEADERS.JSON,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
import assert from 'assert';
|
||||
import { fork } from 'child_process';
|
||||
|
||||
import { HTTP_STATUS } from '@verdaccio/core';
|
||||
|
||||
import { CREDENTIALS } from './constants';
|
||||
import { IServerBridge } from './server';
|
||||
import { IServerProcess, IVerdaccioConfig } from './types';
|
||||
|
||||
const defaultBinPath = require.resolve('verdaccio/bin/verdaccio');
|
||||
|
||||
export default class VerdaccioProcess implements IServerProcess {
|
||||
private bridge: IServerBridge;
|
||||
private config: IVerdaccioConfig;
|
||||
private childFork: any;
|
||||
private isDebug: boolean;
|
||||
private silence: boolean;
|
||||
|
||||
public constructor(
|
||||
config: IVerdaccioConfig,
|
||||
bridge: IServerBridge,
|
||||
silence = true,
|
||||
isDebug = false
|
||||
) {
|
||||
this.config = config;
|
||||
this.bridge = bridge;
|
||||
this.silence = silence;
|
||||
this.isDebug = isDebug;
|
||||
}
|
||||
|
||||
public init(verdaccioPath: string = defaultBinPath): Promise<any> {
|
||||
assert(typeof verdaccioPath === 'string', 'verdaccio bin path string is required.');
|
||||
return new Promise((resolve, reject) => {
|
||||
this._start(verdaccioPath, resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
private _start(verdaccioPath: string, resolve: Function, reject: Function) {
|
||||
let childOptions = {
|
||||
silent: this.silence,
|
||||
};
|
||||
|
||||
if (this.isDebug) {
|
||||
// @ts-ignore
|
||||
const debugPort = parseInt(this.config.port, 10) + 5;
|
||||
|
||||
childOptions = Object.assign({}, childOptions, {
|
||||
execArgv: [`--inspect=${debugPort}`],
|
||||
env: {
|
||||
NODE_DEBUG: 'request',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const { configPath, port } = this.config;
|
||||
this.childFork = fork(verdaccioPath, ['-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.childFork.on('error', (err) => {
|
||||
reject([err, this]);
|
||||
});
|
||||
this.childFork.on('disconnect', (err) => {
|
||||
reject([err, this]);
|
||||
});
|
||||
this.childFork.on('exit', (err) => {
|
||||
reject([err, this]);
|
||||
});
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
return this.childFork.kill('SIGINT');
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
export interface IVerdaccioConfig {
|
||||
storagePath: string;
|
||||
configPath: string;
|
||||
domainPath: string;
|
||||
port: number | string;
|
||||
}
|
||||
|
||||
export interface IServerProcess {
|
||||
init(binPath: string): Promise<any>;
|
||||
stop(): void;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import { pseudoRandomBytes } from 'crypto';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { Version } from '@verdaccio/types';
|
||||
|
||||
// @deprecated use await fileUtils.createTempFolder('verdaccio-test')
|
||||
export function generateRamdonStorage() {
|
||||
const tempStorage = pseudoRandomBytes(5).toString('hex');
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), '/verdaccio-test'));
|
||||
|
||||
return path.join(tempRoot, tempStorage);
|
||||
}
|
||||
|
||||
export function generateNewVersion(
|
||||
pkgName: string,
|
||||
version: string,
|
||||
shashum = '238e7641e59508dc9c20eb4ad37a8aa57ab777b4'
|
||||
): Version {
|
||||
// $FlowFixMe
|
||||
return {
|
||||
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',
|
||||
},
|
||||
dist: {
|
||||
integrity:
|
||||
'sha512-zVEqt1JUCOPsash9q4wMkJEDPD+QCx95TRhQII+JnoS31uBUKoZxhzvvUJCcLVy2CQG4Q' +
|
||||
'dwXARU7dYWPnrwhGg==',
|
||||
shasum: shashum,
|
||||
tarball: `http:\/\/localhost:4873\/${pkgName}\/-\/${pkgName}-${version}.tgz`,
|
||||
},
|
||||
};
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import { IVerdaccioConfig } from './types';
|
||||
|
||||
export class VerdaccioConfig implements IVerdaccioConfig {
|
||||
public storagePath: string;
|
||||
public configPath: string;
|
||||
public domainPath: string;
|
||||
public port: number;
|
||||
|
||||
public constructor(storagePath: string, configPath: string, domainPath: string, port: number) {
|
||||
this.storagePath = storagePath;
|
||||
this.configPath = configPath;
|
||||
this.domainPath = domainPath;
|
||||
this.port = port;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
storage: ./storage_default_storage
|
||||
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: http://localhost:4873/
|
||||
packages:
|
||||
'@*/*':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'forbidden-place':
|
||||
access: nobody
|
||||
publish: $all
|
||||
'react':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'corrupted-package':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'jquery':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
'auth-package':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
'vue':
|
||||
access: $authenticated
|
||||
publish: $authenticated
|
||||
proxy: npmjs
|
||||
'*':
|
||||
access: $all
|
||||
publish: $all
|
||||
proxy: npmjs
|
||||
log: { type: stdout, format: pretty, level: warn }
|
@ -1,108 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
import { HTTP_STATUS, VerdaccioError } from '@verdaccio/core';
|
||||
|
||||
import { mockServer } from '../src/mock';
|
||||
import smartRequest, { PromiseAssert } from '../src/request';
|
||||
import { IRequestPromise } from '../src/types';
|
||||
|
||||
describe('Request Functional', () => {
|
||||
jest.setTimeout(20000);
|
||||
const mockServerPort = 55547;
|
||||
const domainTest = `http://localhost:${55547}`;
|
||||
const restTest = `${domainTest}/jquery`;
|
||||
let mockRegistry;
|
||||
|
||||
describe('Request Functional', () => {
|
||||
test('PromiseAssert', () => {
|
||||
expect(_.isFunction(smartRequest)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('basic resolve', (done) => {
|
||||
const requestPromise: IRequestPromise = new PromiseAssert((resolve) => {
|
||||
resolve(1);
|
||||
});
|
||||
// @ts-ignore
|
||||
requestPromise.then((result) => {
|
||||
expect(result).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('smartRequest Rest', () => {
|
||||
beforeAll(async () => {
|
||||
const binPath = require.resolve('verdaccio/bin/verdaccio');
|
||||
mockRegistry = await mockServer(mockServerPort).init(binPath);
|
||||
});
|
||||
|
||||
afterAll(function (done) {
|
||||
const [registry, pid] = mockRegistry;
|
||||
registry.stop();
|
||||
console.log(`registry ${pid} has been stopped`);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('basic rest', (done) => {
|
||||
const options: any = {
|
||||
url: restTest,
|
||||
method: 'GET',
|
||||
};
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
test('basic ping status and empty response', (done) => {
|
||||
const options: any = {
|
||||
url: `${domainTest}/-/ping`,
|
||||
method: 'GET',
|
||||
};
|
||||
// @ts-ignore
|
||||
smartRequest(options)
|
||||
.status(HTTP_STATUS.OK)
|
||||
.then((result) => {
|
||||
expect(JSON.parse(result)).toEqual({});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('basic check status 404', (done) => {
|
||||
const options: any = {
|
||||
url: 'http://www.google.fake',
|
||||
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();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build"
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.reference.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/**/*.test.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../config"
|
||||
},
|
||||
{
|
||||
"path": "../../utils"
|
||||
}
|
||||
]
|
||||
}
|
@ -47,7 +47,6 @@
|
||||
"verdaccio-htpasswd": "workspace:11.0.0-6-next.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/mock": "workspace:6.0.0-6-next.15",
|
||||
"@verdaccio/auth": "workspace:6.0.0-6-next.22",
|
||||
"@verdaccio/core": "workspace:6.0.0-6-next.5",
|
||||
"@verdaccio/config": "workspace:6.0.0-6-next.14",
|
||||
|
@ -1,78 +1,78 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
// /* eslint-disable no-unused-vars */
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
// we need this for notifications
|
||||
import { setup } from '@verdaccio/logger';
|
||||
import { IServerBridge } from '@verdaccio/mock';
|
||||
// /* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
// // we need this for notifications
|
||||
// import { setup } from '@verdaccio/logger';
|
||||
// import { IServerBridge } from '@verdaccio/mock';
|
||||
|
||||
import adduser from './adduser/adduser';
|
||||
import logout from './adduser/logout';
|
||||
import basic from './basic/basic';
|
||||
import packageAccess from './package/access';
|
||||
import packageGzip from './package/gzip';
|
||||
import packageScoped from './package/scoped';
|
||||
import race from './performance/race';
|
||||
import pluginsAuth from './plugins/auth';
|
||||
import middleware from './plugins/middleware';
|
||||
import readme from './readme/readme';
|
||||
import incomplete from './sanity/incomplete';
|
||||
import mirror from './sanity/mirror';
|
||||
import nullstorage from './sanity/nullstorage';
|
||||
// import simpleSearch from './search/simple.search';
|
||||
import racycrash from './sanity/racycrash';
|
||||
import security from './sanity/security';
|
||||
import gh29 from './scenarios/gh29';
|
||||
import addtag from './tags/addtag';
|
||||
import distTagsMerge from './tags/dist-tags-merge';
|
||||
import tags from './tags/tags';
|
||||
import upLinkCache from './uplinks/cache';
|
||||
import uplinkTimeout from './uplinks/timeout';
|
||||
// import adduser from './adduser/adduser';
|
||||
// import logout from './adduser/logout';
|
||||
// import basic from './basic/basic';
|
||||
// import packageAccess from './package/access';
|
||||
// import packageGzip from './package/gzip';
|
||||
// import packageScoped from './package/scoped';
|
||||
// import race from './performance/race';
|
||||
// import pluginsAuth from './plugins/auth';
|
||||
// import middleware from './plugins/middleware';
|
||||
// import readme from './readme/readme';
|
||||
// import incomplete from './sanity/incomplete';
|
||||
// import mirror from './sanity/mirror';
|
||||
// import nullstorage from './sanity/nullstorage';
|
||||
// // import simpleSearch from './search/simple.search';
|
||||
// import racycrash from './sanity/racycrash';
|
||||
// import security from './sanity/security';
|
||||
// import gh29 from './scenarios/gh29';
|
||||
// import addtag from './tags/addtag';
|
||||
// import distTagsMerge from './tags/dist-tags-merge';
|
||||
// import tags from './tags/tags';
|
||||
// import upLinkCache from './uplinks/cache';
|
||||
// import uplinkTimeout from './uplinks/timeout';
|
||||
|
||||
setup({});
|
||||
// setup({});
|
||||
|
||||
describe('functional test verdaccio', function () {
|
||||
jest.setTimeout(20000);
|
||||
// @ts-ignore
|
||||
const server1: IServerBridge = global.__SERVERS__[0];
|
||||
// @ts-ignore
|
||||
const server2 = global.__SERVERS__[1];
|
||||
// @ts-ignore
|
||||
const server3 = global.__SERVERS__[2];
|
||||
// @ts-ignore
|
||||
// const simpleServer = global.__WEB_SERVER__.server;
|
||||
// describe('functional test verdaccio', function () {
|
||||
// jest.setTimeout(20000);
|
||||
// // @ts-ignore
|
||||
// const server1: IServerBridge = global.__SERVERS__[0];
|
||||
// // @ts-ignore
|
||||
// const server2 = global.__SERVERS__[1];
|
||||
// // @ts-ignore
|
||||
// const server3 = global.__SERVERS__[2];
|
||||
// // @ts-ignore
|
||||
// // const simpleServer = global.__WEB_SERVER__.server;
|
||||
|
||||
// list of test
|
||||
// note: order of the following calls is important, the reason is legacy code.
|
||||
packageAccess(server1);
|
||||
// FIXME: use real cli test for this
|
||||
gh29(server1, server2);
|
||||
tags(server1);
|
||||
// packageGzip(server1, simpleServer);
|
||||
// incomplete(server1, simpleServer);
|
||||
mirror(server1, server2);
|
||||
distTagsMerge(server1, server2, server3);
|
||||
readme(server1, server2);
|
||||
nullstorage(server1, server2);
|
||||
middleware(server2);
|
||||
race(server1);
|
||||
// racycrash(server1, simpleServer);
|
||||
packageScoped(server1, server2);
|
||||
security(server1);
|
||||
addtag(server1);
|
||||
pluginsAuth(server2);
|
||||
uplinkTimeout(server1, server2, server3);
|
||||
// // requires packages published to server1/server2
|
||||
upLinkCache(server1, server2, server3);
|
||||
adduser(server1);
|
||||
logout(server1);
|
||||
basic(server1, server2);
|
||||
// FIXME: use real cli test for this
|
||||
// simpleSearch(server1, server2, simpleServer);
|
||||
});
|
||||
// // list of test
|
||||
// // note: order of the following calls is important, the reason is legacy code.
|
||||
// packageAccess(server1);
|
||||
// // FIXME: use real cli test for this
|
||||
// gh29(server1, server2);
|
||||
// tags(server1);
|
||||
// // packageGzip(server1, simpleServer);
|
||||
// // incomplete(server1, simpleServer);
|
||||
// mirror(server1, server2);
|
||||
// distTagsMerge(server1, server2, server3);
|
||||
// readme(server1, server2);
|
||||
// nullstorage(server1, server2);
|
||||
// middleware(server2);
|
||||
// race(server1);
|
||||
// // racycrash(server1, simpleServer);
|
||||
// packageScoped(server1, server2);
|
||||
// security(server1);
|
||||
// addtag(server1);
|
||||
// pluginsAuth(server2);
|
||||
// uplinkTimeout(server1, server2, server3);
|
||||
// // // requires packages published to server1/server2
|
||||
// upLinkCache(server1, server2, server3);
|
||||
// adduser(server1);
|
||||
// logout(server1);
|
||||
// basic(server1, server2);
|
||||
// // FIXME: use real cli test for this
|
||||
// // simpleSearch(server1, server2, simpleServer);
|
||||
// });
|
||||
|
||||
process.on('unhandledRejection', function (err) {
|
||||
console.error('unhandledRejection', err);
|
||||
process.nextTick(function () {
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
// process.on('unhandledRejection', function (err) {
|
||||
// console.error('unhandledRejection', err);
|
||||
// process.nextTick(function () {
|
||||
// throw err;
|
||||
// });
|
||||
// });
|
||||
|
610
pnpm-lock.yaml
generated
610
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user