@verdaccio/api 6.0.0-6-next.23 → 6.0.0-6-next.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +124 -0
- package/build/dist-tags.js +40 -35
- package/build/dist-tags.js.map +1 -1
- package/build/index.js +1 -7
- package/build/index.js.map +1 -1
- package/build/package.js +33 -28
- package/build/package.js.map +1 -1
- package/build/ping.js.map +1 -1
- package/build/publish.d.ts +79 -22
- package/build/publish.js +89 -313
- package/build/publish.js.map +1 -1
- package/build/search.js.map +1 -1
- package/build/star.js +53 -54
- package/build/star.js.map +1 -1
- package/build/stars.js +6 -6
- package/build/stars.js.map +1 -1
- package/build/user.js +19 -1
- package/build/user.js.map +1 -1
- package/build/v1/profile.js.map +1 -1
- package/build/v1/search.js +2 -4
- package/build/v1/search.js.map +1 -1
- package/build/v1/token.js.map +1 -1
- package/build/whoami.js +11 -25
- package/build/whoami.js.map +1 -1
- package/jest.config.js +8 -1
- package/package.json +71 -69
- package/src/dist-tags.ts +63 -50
- package/src/index.ts +1 -6
- package/src/package.ts +35 -44
- package/src/publish.ts +115 -336
- package/src/star.ts +53 -52
- package/src/stars.ts +9 -11
- package/src/user.ts +19 -2
- package/src/v1/search.ts +3 -3
- package/src/whoami.ts +8 -24
- package/test/integration/_helper.ts +97 -53
- package/test/integration/config/distTag.yaml +25 -0
- package/test/integration/config/package.yaml +4 -9
- package/test/integration/config/ping.yaml +3 -7
- package/test/integration/config/publish.yaml +5 -11
- package/test/integration/config/search.yaml +29 -0
- package/test/integration/config/token.jwt.yaml +27 -0
- package/test/integration/config/token.yaml +19 -0
- package/test/integration/config/user.jwt.yaml +37 -0
- package/test/integration/config/user.yaml +9 -15
- package/test/integration/config/whoami.yaml +5 -12
- package/test/integration/distTag.spec.ts +76 -0
- package/test/integration/package.spec.ts +33 -76
- package/test/integration/ping.spec.ts +4 -3
- package/test/integration/publish.spec.ts +61 -26
- package/test/integration/search.spec.ts +126 -0
- package/test/integration/token.spec.ts +124 -0
- package/test/integration/user.jwt.spec.ts +87 -0
- package/test/integration/user.spec.ts +1 -0
- package/test/integration/whoami.spec.ts +21 -39
- package/test/unit/publish.disabled.ts +252 -0
- package/tsconfig.json +1 -1
- package/__mocks__/@verdaccio/logger/index.js +0 -21
- package/build/utils.d.ts +0 -7
- package/build/utils.js +0 -36
- package/build/utils.js.map +0 -1
- package/src/utils.ts +0 -25
- package/test/unit/__snapshots__/publish.spec.ts.snap +0 -49
- package/test/unit/publish.spec.ts +0 -300
|
@@ -2,32 +2,7 @@ import supertest from 'supertest';
|
|
|
2
2
|
|
|
3
3
|
import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { initializeServer, publishTaggedVersion, publishVersion } from './_helper';
|
|
7
|
-
|
|
8
|
-
const mockApiJWTmiddleware = jest.fn(
|
|
9
|
-
() =>
|
|
10
|
-
(req: $RequestExtend, res: $ResponseExtend, _next): void => {
|
|
11
|
-
req.remote_user = { name: 'foo', groups: [], real_groups: [] };
|
|
12
|
-
_next();
|
|
13
|
-
}
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
jest.mock('@verdaccio/auth', () => ({
|
|
17
|
-
Auth: class {
|
|
18
|
-
apiJWTmiddleware() {
|
|
19
|
-
return mockApiJWTmiddleware();
|
|
20
|
-
}
|
|
21
|
-
allow_access(_d, _f, cb) {
|
|
22
|
-
// always allow access
|
|
23
|
-
cb(null, true);
|
|
24
|
-
}
|
|
25
|
-
allow_publish(_d, _f, cb) {
|
|
26
|
-
// always allow publish
|
|
27
|
-
cb(null, true);
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
}));
|
|
5
|
+
import { initializeServer, publishVersion } from './_helper';
|
|
31
6
|
|
|
32
7
|
describe('package', () => {
|
|
33
8
|
let app;
|
|
@@ -35,57 +10,39 @@ describe('package', () => {
|
|
|
35
10
|
app = await initializeServer('package.yaml');
|
|
36
11
|
});
|
|
37
12
|
|
|
38
|
-
test('should return a package', async () => {
|
|
39
|
-
await publishVersion(app,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.set('Accept', HEADERS.JSON)
|
|
44
|
-
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
45
|
-
.expect(HTTP_STATUS.OK)
|
|
46
|
-
.then((response) => {
|
|
47
|
-
expect(response.body.name).toEqual('foo');
|
|
48
|
-
resolve(response);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('should return a package by version', async () => {
|
|
54
|
-
await publishVersion(app, 'package.yaml', 'foo2', '1.0.0');
|
|
55
|
-
return new Promise((resolve) => {
|
|
56
|
-
supertest(app)
|
|
57
|
-
.get('/foo2/1.0.0')
|
|
58
|
-
.set('Accept', HEADERS.JSON)
|
|
59
|
-
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
60
|
-
.expect(HTTP_STATUS.OK)
|
|
61
|
-
.then((response) => {
|
|
62
|
-
expect(response.body.name).toEqual('foo2');
|
|
63
|
-
resolve(response);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// FIXME: investigate the 404
|
|
69
|
-
test.skip('should return a package by dist-tag', async (done) => {
|
|
70
|
-
// await publishVersion(app, 'package.yaml', 'foo3', '1.0.0');
|
|
71
|
-
await publishVersion(app, 'package.yaml', 'foo-tagged', '1.0.0');
|
|
72
|
-
await publishTaggedVersion(app, 'package.yaml', 'foo-tagged', '1.0.1', 'test');
|
|
73
|
-
return supertest(app)
|
|
74
|
-
.get('/foo-tagged/1.0.1')
|
|
75
|
-
.set('Accept', HEADERS.JSON)
|
|
13
|
+
test.each([['foo'], ['@scope/foo']])('should return a foo private package', async (pkg) => {
|
|
14
|
+
await publishVersion(app, pkg, '1.0.0');
|
|
15
|
+
const response = await supertest(app)
|
|
16
|
+
.get(`/${pkg}`)
|
|
17
|
+
.set(HEADERS.ACCEPT, HEADERS.JSON)
|
|
76
18
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
77
|
-
.expect(HTTP_STATUS.
|
|
78
|
-
|
|
79
|
-
expect(response.body.name).toEqual('foo3');
|
|
80
|
-
done();
|
|
81
|
-
});
|
|
19
|
+
.expect(HTTP_STATUS.OK);
|
|
20
|
+
expect(response.body.name).toEqual(pkg);
|
|
82
21
|
});
|
|
83
22
|
|
|
84
|
-
test('
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
23
|
+
test.each([['foo'], ['@scope/foo']])(
|
|
24
|
+
'should return a foo private package by version',
|
|
25
|
+
async (pkg) => {
|
|
26
|
+
await publishVersion(app, pkg, '1.0.0');
|
|
27
|
+
const response = await supertest(app)
|
|
28
|
+
.get(`/${pkg}`)
|
|
29
|
+
.set(HEADERS.ACCEPT, HEADERS.JSON)
|
|
30
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
31
|
+
.expect(HTTP_STATUS.OK);
|
|
32
|
+
expect(response.body.name).toEqual(pkg);
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
test.each([['foo'], ['@scope/foo']])(
|
|
37
|
+
'should return a foo private package by version',
|
|
38
|
+
async (pkg) => {
|
|
39
|
+
await publishVersion(app, pkg, '1.0.0');
|
|
40
|
+
const response = await supertest(app)
|
|
41
|
+
.get(`/${pkg}`)
|
|
42
|
+
.set(HEADERS.ACCEPT, HEADERS.JSON)
|
|
43
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
44
|
+
.expect(HTTP_STATUS.OK);
|
|
45
|
+
expect(response.body.name).toEqual(pkg);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
91
48
|
});
|
|
@@ -6,11 +6,12 @@ import { initializeServer } from './_helper';
|
|
|
6
6
|
|
|
7
7
|
describe('ping', () => {
|
|
8
8
|
test('should return the reply the ping', async () => {
|
|
9
|
-
|
|
9
|
+
const app = await initializeServer('ping.yaml');
|
|
10
|
+
const response = await supertest(app)
|
|
10
11
|
.get('/-/ping')
|
|
11
12
|
.set('Accept', HEADERS.JSON)
|
|
12
13
|
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
13
|
-
.expect(HTTP_STATUS.OK)
|
|
14
|
-
|
|
14
|
+
.expect(HTTP_STATUS.OK);
|
|
15
|
+
expect(response.body).toEqual({});
|
|
15
16
|
});
|
|
16
17
|
});
|
|
@@ -2,7 +2,7 @@ import supertest from 'supertest';
|
|
|
2
2
|
|
|
3
3
|
import { HTTP_STATUS } from '@verdaccio/core';
|
|
4
4
|
import { API_ERROR, API_MESSAGE, HEADERS, HEADER_TYPE } from '@verdaccio/core';
|
|
5
|
-
import { generatePackageMetadata } from '@verdaccio/helper';
|
|
5
|
+
import { generatePackageMetadata } from '@verdaccio/test-helper';
|
|
6
6
|
|
|
7
7
|
import { $RequestExtend, $ResponseExtend } from '../../types/custom';
|
|
8
8
|
import { initializeServer, publishVersion } from './_helper';
|
|
@@ -60,9 +60,9 @@ describe('publish', () => {
|
|
|
60
60
|
describe('handle invalid publish formats', () => {
|
|
61
61
|
const pkgName = 'test';
|
|
62
62
|
const pkgMetadata = generatePackageMetadata(pkgName, '1.0.0');
|
|
63
|
-
test
|
|
63
|
+
test('should fail on publish a bad _attachments package', async () => {
|
|
64
64
|
const app = await initializeServer('publish.yaml');
|
|
65
|
-
|
|
65
|
+
const response = await supertest(app)
|
|
66
66
|
.put(`/${encodeURIComponent(pkgName)}`)
|
|
67
67
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
68
68
|
.send(
|
|
@@ -73,12 +73,8 @@ describe('publish', () => {
|
|
|
73
73
|
)
|
|
74
74
|
)
|
|
75
75
|
.set('accept', HEADERS.GZIP)
|
|
76
|
-
.expect(HTTP_STATUS.BAD_REQUEST)
|
|
77
|
-
|
|
78
|
-
console.log('response.body', response.body);
|
|
79
|
-
expect(response.body.error).toEqual(API_ERROR.UNSUPORTED_REGISTRY_CALL);
|
|
80
|
-
done();
|
|
81
|
-
});
|
|
76
|
+
.expect(HTTP_STATUS.BAD_REQUEST);
|
|
77
|
+
expect(response.body.error).toEqual(API_ERROR.UNSUPORTED_REGISTRY_CALL);
|
|
82
78
|
});
|
|
83
79
|
|
|
84
80
|
test('should fail on publish a bad versions package', async () => {
|
|
@@ -97,7 +93,6 @@ describe('publish', () => {
|
|
|
97
93
|
.set('accept', HEADERS.GZIP)
|
|
98
94
|
.expect(HTTP_STATUS.BAD_REQUEST)
|
|
99
95
|
.then((response) => {
|
|
100
|
-
console.log('response.body', response.body);
|
|
101
96
|
expect(response.body.error).toEqual(API_ERROR.UNSUPORTED_REGISTRY_CALL);
|
|
102
97
|
resolve(response);
|
|
103
98
|
});
|
|
@@ -109,7 +104,7 @@ describe('publish', () => {
|
|
|
109
104
|
test('should publish a package', async () => {
|
|
110
105
|
const app = await initializeServer('publish.yaml');
|
|
111
106
|
return new Promise((resolve) => {
|
|
112
|
-
publishVersion(app, '
|
|
107
|
+
publishVersion(app, 'foo', '1.0.0')
|
|
113
108
|
.expect(HTTP_STATUS.CREATED)
|
|
114
109
|
.then((response) => {
|
|
115
110
|
expect(response.body.ok).toEqual(API_MESSAGE.PKG_CREATED);
|
|
@@ -126,13 +121,7 @@ describe('publish', () => {
|
|
|
126
121
|
supertest(app)
|
|
127
122
|
.put(`/${encodeURIComponent(pkgName)}`)
|
|
128
123
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
129
|
-
.send(
|
|
130
|
-
JSON.stringify(
|
|
131
|
-
Object.assign({}, pkgMetadata, {
|
|
132
|
-
_attachments: null,
|
|
133
|
-
})
|
|
134
|
-
)
|
|
135
|
-
)
|
|
124
|
+
.send(JSON.stringify(Object.assign({}, pkgMetadata)))
|
|
136
125
|
.set('accept', HEADERS.GZIP)
|
|
137
126
|
.expect(HTTP_STATUS.CREATED)
|
|
138
127
|
.then((response) => {
|
|
@@ -173,12 +162,11 @@ describe('publish', () => {
|
|
|
173
162
|
|
|
174
163
|
test('should fails on publish a duplicated package', async () => {
|
|
175
164
|
const app = await initializeServer('publish.yaml');
|
|
176
|
-
await publishVersion(app, '
|
|
165
|
+
await publishVersion(app, 'foo', '1.0.0');
|
|
177
166
|
return new Promise((resolve) => {
|
|
178
|
-
publishVersion(app, '
|
|
167
|
+
publishVersion(app, 'foo', '1.0.0')
|
|
179
168
|
.expect(HTTP_STATUS.CONFLICT)
|
|
180
169
|
.then((response) => {
|
|
181
|
-
console.log('response.body', response.body);
|
|
182
170
|
expect(response.body.error).toEqual(API_ERROR.PACKAGE_EXIST);
|
|
183
171
|
resolve(response);
|
|
184
172
|
});
|
|
@@ -186,14 +174,61 @@ describe('publish', () => {
|
|
|
186
174
|
});
|
|
187
175
|
|
|
188
176
|
describe('unpublish a package', () => {
|
|
189
|
-
|
|
177
|
+
test('should unpublish entirely a package', async () => {
|
|
178
|
+
const app = await initializeServer('publish.yaml');
|
|
179
|
+
await publishVersion(app, 'foo', '1.0.0');
|
|
180
|
+
const response = await supertest(app)
|
|
181
|
+
// FIXME: should be filtered by revision to avoid
|
|
182
|
+
// conflicts
|
|
183
|
+
.delete(`/${encodeURIComponent('foo')}/-rev/xxx`)
|
|
184
|
+
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
185
|
+
.expect(HTTP_STATUS.CREATED);
|
|
186
|
+
expect(response.body.ok).toEqual(API_MESSAGE.PKG_REMOVED);
|
|
187
|
+
// package should be completely un published
|
|
188
|
+
await supertest(app)
|
|
189
|
+
.get('/foo')
|
|
190
|
+
.set('Accept', HEADERS.JSON)
|
|
191
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
192
|
+
.expect(HTTP_STATUS.NOT_FOUND);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test('should fails unpublish entirely a package', async () => {
|
|
196
|
+
const app = await initializeServer('publish.yaml');
|
|
197
|
+
const response = await supertest(app)
|
|
198
|
+
.delete(`/${encodeURIComponent('foo')}/-rev/1cf3-fe3`)
|
|
199
|
+
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
200
|
+
.expect(HTTP_STATUS.NOT_FOUND);
|
|
201
|
+
expect(response.body.error).toEqual(API_ERROR.NO_PACKAGE);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('should fails remove a tarball of a package does not exist', async () => {
|
|
205
|
+
const app = await initializeServer('publish.yaml');
|
|
206
|
+
const response = await supertest(app)
|
|
207
|
+
.delete(`/foo/-/foo-1.0.3.tgz/-rev/revision`)
|
|
208
|
+
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
209
|
+
.expect(HTTP_STATUS.NOT_FOUND);
|
|
210
|
+
expect(response.body.error).toEqual(API_ERROR.NO_PACKAGE);
|
|
211
|
+
});
|
|
190
212
|
|
|
191
|
-
|
|
192
|
-
app = await initializeServer('publish.yaml');
|
|
193
|
-
await publishVersion(app, '
|
|
213
|
+
test('should fails on try remove a tarball does not exist', async () => {
|
|
214
|
+
const app = await initializeServer('publish.yaml');
|
|
215
|
+
await publishVersion(app, 'foo', '1.0.0');
|
|
216
|
+
const response = await supertest(app)
|
|
217
|
+
.delete(`/foo/-/foo-1.0.3.tgz/-rev/revision`)
|
|
218
|
+
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
219
|
+
.expect(HTTP_STATUS.NOT_FOUND);
|
|
220
|
+
expect(response.body.error).toEqual(API_ERROR.NO_SUCH_FILE);
|
|
194
221
|
});
|
|
195
222
|
|
|
196
|
-
test('should
|
|
223
|
+
test('should remove a tarball that does exist', async () => {
|
|
224
|
+
const app = await initializeServer('publish.yaml');
|
|
225
|
+
await publishVersion(app, 'foo', '1.0.0');
|
|
226
|
+
const response = await supertest(app)
|
|
227
|
+
.delete(`/foo/-/foo-1.0.0.tgz/-rev/revision`)
|
|
228
|
+
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
229
|
+
.expect(HTTP_STATUS.CREATED);
|
|
230
|
+
expect(response.body.ok).toEqual(API_MESSAGE.TARBALL_REMOVED);
|
|
231
|
+
});
|
|
197
232
|
});
|
|
198
233
|
|
|
199
234
|
describe('star a package', () => {});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import MockDate from 'mockdate';
|
|
2
|
+
import supertest from 'supertest';
|
|
3
|
+
|
|
4
|
+
import { HEADERS, HEADER_TYPE, HTTP_STATUS } from '@verdaccio/core';
|
|
5
|
+
|
|
6
|
+
import { createUser, initializeServer, publishVersionWithToken } from './_helper';
|
|
7
|
+
|
|
8
|
+
describe('search', () => {
|
|
9
|
+
let app;
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
app = await initializeServer('search.yaml');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('search authenticated', () => {
|
|
15
|
+
test.each([['foo']])('should return a foo private package', async (pkg) => {
|
|
16
|
+
const mockDate = '2018-01-14T11:17:40.712Z';
|
|
17
|
+
MockDate.set(mockDate);
|
|
18
|
+
const res = await createUser(app, 'test', 'test');
|
|
19
|
+
await publishVersionWithToken(app, pkg, '1.0.0', res.body.token);
|
|
20
|
+
// this should not be displayed as part of the search
|
|
21
|
+
await publishVersionWithToken(app, 'private-auth', '1.0.0', res.body.token);
|
|
22
|
+
const response = await supertest(app)
|
|
23
|
+
.get(
|
|
24
|
+
`/-/v1/search?text=${encodeURIComponent(
|
|
25
|
+
pkg
|
|
26
|
+
)}&size=2000&from=0&quality=1&popularity=0.1&maintenance=0.1`
|
|
27
|
+
)
|
|
28
|
+
.set(HEADERS.ACCEPT, HEADERS.JSON)
|
|
29
|
+
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
30
|
+
.expect(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
31
|
+
.expect(HTTP_STATUS.OK);
|
|
32
|
+
expect(response.body).toEqual({
|
|
33
|
+
objects: [
|
|
34
|
+
{
|
|
35
|
+
package: {
|
|
36
|
+
author: {
|
|
37
|
+
email: 'user@domain.com',
|
|
38
|
+
name: 'User NPM',
|
|
39
|
+
},
|
|
40
|
+
date: mockDate,
|
|
41
|
+
description: 'package generated',
|
|
42
|
+
keywords: [],
|
|
43
|
+
links: {
|
|
44
|
+
npm: '',
|
|
45
|
+
},
|
|
46
|
+
name: pkg,
|
|
47
|
+
publisher: {},
|
|
48
|
+
scope: '',
|
|
49
|
+
version: '1.0.0',
|
|
50
|
+
},
|
|
51
|
+
score: {
|
|
52
|
+
detail: {
|
|
53
|
+
maintenance: 0,
|
|
54
|
+
popularity: 1,
|
|
55
|
+
quality: 1,
|
|
56
|
+
},
|
|
57
|
+
final: 1,
|
|
58
|
+
},
|
|
59
|
+
searchScore: 1,
|
|
60
|
+
verdaccioPkgCached: false,
|
|
61
|
+
verdaccioPrivate: true,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
time: 'Sun, 14 Jan 2018 11:17:40 GMT',
|
|
65
|
+
total: 1,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test.each([['@scope/foo']])('should return a scoped foo private package', async (pkg) => {
|
|
70
|
+
const mockDate = '2018-01-14T11:17:40.712Z';
|
|
71
|
+
MockDate.set(mockDate);
|
|
72
|
+
const res = await createUser(app, 'test', 'test');
|
|
73
|
+
await publishVersionWithToken(app, pkg, '1.0.0', res.body.token);
|
|
74
|
+
// this should not be displayed as part of the search
|
|
75
|
+
await publishVersionWithToken(app, '@private/auth', '1.0.0', res.body.token);
|
|
76
|
+
const response = await supertest(app)
|
|
77
|
+
.get(
|
|
78
|
+
`/-/v1/search?text=${encodeURIComponent(
|
|
79
|
+
pkg
|
|
80
|
+
)}&size=2000&from=0&quality=1&popularity=0.1&maintenance=0.1`
|
|
81
|
+
)
|
|
82
|
+
.set(HEADERS.ACCEPT, HEADERS.JSON)
|
|
83
|
+
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
|
84
|
+
.expect(HEADERS.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
85
|
+
.expect(HTTP_STATUS.OK);
|
|
86
|
+
expect(response.body).toEqual({
|
|
87
|
+
objects: [
|
|
88
|
+
{
|
|
89
|
+
package: {
|
|
90
|
+
author: {
|
|
91
|
+
email: 'user@domain.com',
|
|
92
|
+
name: 'User NPM',
|
|
93
|
+
},
|
|
94
|
+
date: mockDate,
|
|
95
|
+
description: 'package generated',
|
|
96
|
+
keywords: [],
|
|
97
|
+
links: {
|
|
98
|
+
npm: '',
|
|
99
|
+
},
|
|
100
|
+
name: pkg,
|
|
101
|
+
publisher: {},
|
|
102
|
+
scope: '@scope',
|
|
103
|
+
version: '1.0.0',
|
|
104
|
+
},
|
|
105
|
+
score: {
|
|
106
|
+
detail: {
|
|
107
|
+
maintenance: 0,
|
|
108
|
+
popularity: 1,
|
|
109
|
+
quality: 1,
|
|
110
|
+
},
|
|
111
|
+
final: 1,
|
|
112
|
+
},
|
|
113
|
+
searchScore: 1,
|
|
114
|
+
verdaccioPkgCached: false,
|
|
115
|
+
verdaccioPrivate: true,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
time: 'Sun, 14 Jan 2018 11:17:40 GMT',
|
|
119
|
+
total: 1,
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe('error handling', () => {
|
|
124
|
+
test.todo('should able to abort the request');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import supertest from 'supertest';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
API_ERROR,
|
|
6
|
+
HEADERS,
|
|
7
|
+
HEADER_TYPE,
|
|
8
|
+
HTTP_STATUS,
|
|
9
|
+
SUPPORT_ERRORS,
|
|
10
|
+
TOKEN_BEARER,
|
|
11
|
+
} from '@verdaccio/core';
|
|
12
|
+
import { buildToken } from '@verdaccio/utils';
|
|
13
|
+
|
|
14
|
+
import { deleteTokenCLI, generateTokenCLI, getNewToken, initializeServer } from './_helper';
|
|
15
|
+
|
|
16
|
+
describe('token', () => {
|
|
17
|
+
describe('basics', () => {
|
|
18
|
+
test.each([['token.yaml'], ['token.jwt.yaml']])('should list empty tokens', async (conf) => {
|
|
19
|
+
const app = await initializeServer(conf);
|
|
20
|
+
const token = await getNewToken(app, { name: 'jota_token', password: 'secretPass' });
|
|
21
|
+
const response = await supertest(app)
|
|
22
|
+
.get('/-/npm/v1/tokens')
|
|
23
|
+
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
|
|
24
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
25
|
+
.expect(HTTP_STATUS.OK);
|
|
26
|
+
expect(response.body.objects).toHaveLength(0);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test.each([['token.yaml'], ['token.jwt.yaml']])('should generate one token', async (conf) => {
|
|
30
|
+
const app = await initializeServer(conf);
|
|
31
|
+
const credentials = { name: 'jota_token', password: 'secretPass' };
|
|
32
|
+
const token = await getNewToken(app, credentials);
|
|
33
|
+
await generateTokenCLI(app, token, {
|
|
34
|
+
password: credentials.password,
|
|
35
|
+
readonly: false,
|
|
36
|
+
cidr_whitelist: [],
|
|
37
|
+
});
|
|
38
|
+
const response = await supertest(app)
|
|
39
|
+
.get('/-/npm/v1/tokens')
|
|
40
|
+
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
|
|
41
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
42
|
+
.expect(HTTP_STATUS.OK);
|
|
43
|
+
const { objects, urls } = response.body;
|
|
44
|
+
|
|
45
|
+
expect(objects).toHaveLength(1);
|
|
46
|
+
const [tokenGenerated] = objects;
|
|
47
|
+
expect(tokenGenerated.user).toEqual(credentials.name);
|
|
48
|
+
expect(tokenGenerated.readonly).toBeFalsy();
|
|
49
|
+
expect(tokenGenerated.token).toMatch(/.../);
|
|
50
|
+
expect(_.isString(tokenGenerated.created)).toBeTruthy();
|
|
51
|
+
|
|
52
|
+
// we don't support pagination yet
|
|
53
|
+
expect(urls.next).toEqual('');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test.each([['token.yaml'], ['token.jwt.yaml']])('should delete a token', async (conf) => {
|
|
57
|
+
const app = await initializeServer(conf);
|
|
58
|
+
const credentials = { name: 'jota_token', password: 'secretPass' };
|
|
59
|
+
const token = await getNewToken(app, credentials);
|
|
60
|
+
const response = await generateTokenCLI(app, token, {
|
|
61
|
+
password: credentials.password,
|
|
62
|
+
readonly: false,
|
|
63
|
+
cidr_whitelist: [],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const key = response.body.key;
|
|
67
|
+
await deleteTokenCLI(app, token, key);
|
|
68
|
+
const response2 = await supertest(app)
|
|
69
|
+
.get('/-/npm/v1/tokens')
|
|
70
|
+
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, token))
|
|
71
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
72
|
+
.expect(HTTP_STATUS.OK);
|
|
73
|
+
const { objects } = response2.body;
|
|
74
|
+
expect(objects).toHaveLength(0);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('handle errors', () => {
|
|
79
|
+
test.each([['token.yaml'], ['token.jwt.yaml']])('should delete a token', async (conf) => {
|
|
80
|
+
const app = await initializeServer(conf);
|
|
81
|
+
const credentials = { name: 'jota_token', password: 'secretPass' };
|
|
82
|
+
const token = await getNewToken(app, credentials);
|
|
83
|
+
const resp = await generateTokenCLI(app, token, {
|
|
84
|
+
password: 'wrongPassword',
|
|
85
|
+
readonly: false,
|
|
86
|
+
cidr_whitelist: [],
|
|
87
|
+
});
|
|
88
|
+
expect(resp.body.error).toEqual(API_ERROR.BAD_USERNAME_PASSWORD);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test.each([['token.yaml'], ['token.jwt.yaml']])(
|
|
92
|
+
'should fail if readonly is missing',
|
|
93
|
+
async (conf) => {
|
|
94
|
+
const app = await initializeServer(conf);
|
|
95
|
+
const credentials = { name: 'jota_token', password: 'secretPass' };
|
|
96
|
+
const token = await getNewToken(app, credentials);
|
|
97
|
+
const resp = await generateTokenCLI(app, token, {
|
|
98
|
+
password: credentials.password,
|
|
99
|
+
cidr_whitelist: [],
|
|
100
|
+
});
|
|
101
|
+
expect(resp.body.error).toEqual(SUPPORT_ERRORS.PARAMETERS_NOT_VALID);
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test.each([['token.yaml'], ['token.jwt.yaml']])(
|
|
107
|
+
'should fail if cidr_whitelist is missing',
|
|
108
|
+
async (conf) => {
|
|
109
|
+
const app = await initializeServer(conf);
|
|
110
|
+
const credentials = { name: 'jota_token', password: 'secretPass' };
|
|
111
|
+
const token = await getNewToken(app, credentials);
|
|
112
|
+
const resp = await generateTokenCLI(app, token, {
|
|
113
|
+
password: credentials.password,
|
|
114
|
+
readonly: false,
|
|
115
|
+
});
|
|
116
|
+
expect(resp.body.error).toEqual(SUPPORT_ERRORS.PARAMETERS_NOT_VALID);
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
test.todo('handle failure if delete token');
|
|
121
|
+
test.todo('handle failure if getApiToken fails');
|
|
122
|
+
test.todo('handle failure if token creating fails');
|
|
123
|
+
test.todo('handle failure if token list fails');
|
|
124
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import nock from 'nock';
|
|
2
|
+
import supertest from 'supertest';
|
|
3
|
+
|
|
4
|
+
import { API_ERROR, HEADERS, HEADER_TYPE, HTTP_STATUS, TOKEN_BEARER } from '@verdaccio/core';
|
|
5
|
+
import { generateRemotePackageMetadata } from '@verdaccio/test-helper';
|
|
6
|
+
import { buildToken } from '@verdaccio/utils';
|
|
7
|
+
|
|
8
|
+
import { createUser, getPackage, initializeServer } from './_helper';
|
|
9
|
+
|
|
10
|
+
const FORBIDDEN_VUE = 'authorization required to access package vue';
|
|
11
|
+
|
|
12
|
+
describe('token', () => {
|
|
13
|
+
describe('basics', () => {
|
|
14
|
+
const FAKE_TOKEN: string = buildToken(TOKEN_BEARER, 'fake');
|
|
15
|
+
test.each([['user.yaml'], ['user.jwt.yaml']])('should test add a new user', async (conf) => {
|
|
16
|
+
const upstreamManifest = generateRemotePackageMetadata(
|
|
17
|
+
'vue',
|
|
18
|
+
'1.0.0',
|
|
19
|
+
'https://registry.verdaccio.org'
|
|
20
|
+
);
|
|
21
|
+
nock('https://registry.verdaccio.org').get(`/vue`).reply(201, upstreamManifest);
|
|
22
|
+
|
|
23
|
+
const app = await initializeServer(conf);
|
|
24
|
+
const credentials = { name: 'JotaJWT', password: 'secretPass' };
|
|
25
|
+
const response = await createUser(app, credentials.name, credentials.password);
|
|
26
|
+
expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
|
|
27
|
+
|
|
28
|
+
const vueResponse = await getPackage(app, response.body.token, 'vue');
|
|
29
|
+
expect(vueResponse.body).toBeDefined();
|
|
30
|
+
expect(vueResponse.body.name).toMatch('vue');
|
|
31
|
+
|
|
32
|
+
const vueFailResp = await getPackage(app, FAKE_TOKEN, 'vue', HTTP_STATUS.UNAUTHORIZED);
|
|
33
|
+
expect(vueFailResp.body.error).toMatch(FORBIDDEN_VUE);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test.each([['user.yaml'], ['user.jwt.yaml']])('should test add a new user', async (conf) => {
|
|
37
|
+
const app = await initializeServer(conf);
|
|
38
|
+
const credentials = { name: 'JotaJWT', password: 'secretPass' };
|
|
39
|
+
const response = await createUser(app, credentials.name, credentials.password);
|
|
40
|
+
expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
|
|
41
|
+
const response2 = await supertest(app)
|
|
42
|
+
.put(`/-/user/org.couchdb.user:${credentials.name}`)
|
|
43
|
+
.send({
|
|
44
|
+
name: credentials.name,
|
|
45
|
+
password: credentials.password,
|
|
46
|
+
})
|
|
47
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
48
|
+
.expect(HTTP_STATUS.CONFLICT);
|
|
49
|
+
expect(response2.body.error).toBe(API_ERROR.USERNAME_ALREADY_REGISTERED);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test.each([['user.yaml'], ['user.jwt.yaml']])(
|
|
53
|
+
'should fails on login if user credentials are invalid even if jwt',
|
|
54
|
+
async (conf) => {
|
|
55
|
+
const app = await initializeServer(conf);
|
|
56
|
+
const credentials = { name: 'newFailsUser', password: 'secretPass' };
|
|
57
|
+
const response = await createUser(app, credentials.name, credentials.password);
|
|
58
|
+
expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
|
|
59
|
+
const response2 = await supertest(app)
|
|
60
|
+
.put(`/-/user/org.couchdb.user:${credentials.name}`)
|
|
61
|
+
.send({
|
|
62
|
+
name: credentials.name,
|
|
63
|
+
password: 'BAD_PASSWORD',
|
|
64
|
+
})
|
|
65
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
66
|
+
.expect(HTTP_STATUS.UNAUTHORIZED);
|
|
67
|
+
expect(response2.body.error).toBe(API_ERROR.UNAUTHORIZED_ACCESS);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
test.each([['user.yaml'], ['user.jwt.yaml']])(
|
|
72
|
+
'should verify if user is logged',
|
|
73
|
+
async (conf) => {
|
|
74
|
+
const app = await initializeServer(conf);
|
|
75
|
+
const credentials = { name: 'jota', password: 'secretPass' };
|
|
76
|
+
const response = await createUser(app, credentials.name, credentials.password);
|
|
77
|
+
expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
|
|
78
|
+
const response2 = await supertest(app)
|
|
79
|
+
.get(`/-/user/org.couchdb.user:${credentials.name}`)
|
|
80
|
+
.set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, response.body.token))
|
|
81
|
+
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
|
|
82
|
+
.expect(HTTP_STATUS.OK);
|
|
83
|
+
expect(response2.body.ok).toBe(`you are authenticated as '${credentials.name}'`);
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
});
|