@verdaccio/api 8.1.0-next-8.12 → 8.1.0-next-8.13
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/README.md +17 -10
- package/package.json +16 -12
- package/.babelrc +0 -3
- package/.eslintrc +0 -5
- package/CHANGELOG.md +0 -2152
- package/src/dist-tags.ts +0 -106
- package/src/index.ts +0 -65
- package/src/package.ts +0 -117
- package/src/ping.ts +0 -14
- package/src/publish.ts +0 -262
- package/src/search.ts +0 -12
- package/src/stars.ts +0 -37
- package/src/user.ts +0 -179
- package/src/v1/profile.ts +0 -113
- package/src/v1/search.ts +0 -85
- package/src/v1/token.ts +0 -157
- package/src/whoami.ts +0 -26
- package/test/.eslintrc +0 -8
- package/test/integration/_helper.ts +0 -198
- package/test/integration/config/distTag.yaml +0 -25
- package/test/integration/config/owner.yaml +0 -24
- package/test/integration/config/package.yaml +0 -25
- package/test/integration/config/ping.yaml +0 -26
- package/test/integration/config/profile.yaml +0 -27
- package/test/integration/config/publish-proxy.yaml +0 -26
- package/test/integration/config/publish.yaml +0 -24
- package/test/integration/config/search.yaml +0 -29
- package/test/integration/config/star.yaml +0 -26
- package/test/integration/config/token.jwt.yaml +0 -27
- package/test/integration/config/token.yaml +0 -19
- package/test/integration/config/user.jwt.yaml +0 -37
- package/test/integration/config/user.yaml +0 -30
- package/test/integration/config/whoami.yaml +0 -29
- package/test/integration/distTag.spec.ts +0 -80
- package/test/integration/owner.spec.ts +0 -119
- package/test/integration/package.spec.ts +0 -107
- package/test/integration/ping.spec.ts +0 -18
- package/test/integration/profile.spec.ts +0 -112
- package/test/integration/publish.spec.ts +0 -232
- package/test/integration/search.spec.ts +0 -139
- package/test/integration/star.spec.ts +0 -74
- package/test/integration/token.spec.ts +0 -125
- package/test/integration/user.spec.ts +0 -222
- package/test/integration/whoami.spec.ts +0 -36
- package/test/unit/publish.disabled.ts +0 -252
- package/test/unit/validate.api.params.middleware.spec.ts +0 -44
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -41
- package/types/custom.d.ts +0 -16
package/src/user.ts
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import buildDebug from 'debug';
|
|
2
|
-
import { Response, Router } from 'express';
|
|
3
|
-
|
|
4
|
-
import { getApiToken } from '@verdaccio/auth';
|
|
5
|
-
import { Auth } from '@verdaccio/auth';
|
|
6
|
-
import { createRemoteUser } from '@verdaccio/config';
|
|
7
|
-
import {
|
|
8
|
-
API_ERROR,
|
|
9
|
-
API_MESSAGE,
|
|
10
|
-
HEADERS,
|
|
11
|
-
HTTP_STATUS,
|
|
12
|
-
errorUtils,
|
|
13
|
-
validatioUtils,
|
|
14
|
-
} from '@verdaccio/core';
|
|
15
|
-
import { USER_API_ENDPOINTS, rateLimit } from '@verdaccio/middleware';
|
|
16
|
-
import { Logger } from '@verdaccio/types';
|
|
17
|
-
import { Config, RemoteUser } from '@verdaccio/types';
|
|
18
|
-
import { getAuthenticatedMessage, mask } from '@verdaccio/utils';
|
|
19
|
-
|
|
20
|
-
import { $NextFunctionVer, $RequestExtend } from '../types/custom';
|
|
21
|
-
|
|
22
|
-
const debug = buildDebug('verdaccio:api:user');
|
|
23
|
-
|
|
24
|
-
export default function (route: Router, auth: Auth, config: Config, logger: Logger): void {
|
|
25
|
-
route.get(
|
|
26
|
-
USER_API_ENDPOINTS.get_user,
|
|
27
|
-
rateLimit(config?.userRateLimit),
|
|
28
|
-
function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
|
|
29
|
-
debug('verifying user');
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
!req.remote_user ||
|
|
33
|
-
typeof req.remote_user.name !== 'string' ||
|
|
34
|
-
req.remote_user.name === ''
|
|
35
|
-
) {
|
|
36
|
-
debug('user not logged in');
|
|
37
|
-
res.status(HTTP_STATUS.OK);
|
|
38
|
-
return next({ ok: false });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const username = req.params.org_couchdb_user.split(':')[1];
|
|
42
|
-
const message = getAuthenticatedMessage(req.remote_user.name);
|
|
43
|
-
debug('user authenticated message %o', message);
|
|
44
|
-
res.status(HTTP_STATUS.OK);
|
|
45
|
-
next({
|
|
46
|
-
// 'npm owner' requires user info
|
|
47
|
-
// TODO: we don't have the email
|
|
48
|
-
name: username,
|
|
49
|
-
email: '',
|
|
50
|
-
ok: message,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
57
|
-
* body example
|
|
58
|
-
* req.body = {
|
|
59
|
-
_id: "org.couchdb.user:jjjj",
|
|
60
|
-
name: "jjjj",
|
|
61
|
-
password: "jjjj",
|
|
62
|
-
type: "user",
|
|
63
|
-
roles: [],
|
|
64
|
-
date: "2022-07-08T15:51:04.002Z",
|
|
65
|
-
}
|
|
66
|
-
*
|
|
67
|
-
* @export
|
|
68
|
-
* @param {Router} route
|
|
69
|
-
* @param {Auth} auth
|
|
70
|
-
* @param {Config} config
|
|
71
|
-
*/
|
|
72
|
-
route.put(
|
|
73
|
-
USER_API_ENDPOINTS.add_user,
|
|
74
|
-
rateLimit(config?.userRateLimit),
|
|
75
|
-
function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
|
|
76
|
-
const { name, password } = req.body;
|
|
77
|
-
debug('login or adduser');
|
|
78
|
-
const remoteName = req?.remote_user?.name;
|
|
79
|
-
|
|
80
|
-
if (!validatioUtils.validateUserName(req.params.org_couchdb_user, name)) {
|
|
81
|
-
return next(errorUtils.getBadRequest(API_ERROR.USERNAME_MISMATCH));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (typeof remoteName !== 'undefined' && typeof name === 'string' && remoteName === name) {
|
|
85
|
-
debug('login: no remote user detected');
|
|
86
|
-
auth.authenticate(
|
|
87
|
-
name,
|
|
88
|
-
password,
|
|
89
|
-
async function callbackAuthenticate(err, user): Promise<void> {
|
|
90
|
-
if (err) {
|
|
91
|
-
logger.trace(
|
|
92
|
-
{ name, err },
|
|
93
|
-
'authenticating for user @{username} failed. Error: @{err.message}'
|
|
94
|
-
);
|
|
95
|
-
return next(
|
|
96
|
-
errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.BAD_USERNAME_PASSWORD)
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const restoredRemoteUser: RemoteUser = createRemoteUser(name, user?.groups || []);
|
|
101
|
-
const token = await getApiToken(auth, config, restoredRemoteUser, password);
|
|
102
|
-
debug('login: new token');
|
|
103
|
-
if (!token) {
|
|
104
|
-
return next(errorUtils.getUnauthorized());
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
res.status(HTTP_STATUS.CREATED);
|
|
108
|
-
res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');
|
|
109
|
-
|
|
110
|
-
const message = getAuthenticatedMessage(req.remote_user.name);
|
|
111
|
-
debug('login: created user message %o', message);
|
|
112
|
-
|
|
113
|
-
return next({
|
|
114
|
-
ok: message,
|
|
115
|
-
token,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
} else {
|
|
120
|
-
debug('adduser: %o', name);
|
|
121
|
-
if (
|
|
122
|
-
validatioUtils.validatePassword(
|
|
123
|
-
password,
|
|
124
|
-
config?.serverSettings?.passwordValidationRegex
|
|
125
|
-
) === false
|
|
126
|
-
) {
|
|
127
|
-
debug('adduser: invalid password');
|
|
128
|
-
// eslint-disable-next-line new-cap
|
|
129
|
-
return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
auth.add_user(name, password, async function (err, user): Promise<void> {
|
|
133
|
-
if (err) {
|
|
134
|
-
if (err.status >= HTTP_STATUS.BAD_REQUEST && err.status < HTTP_STATUS.INTERNAL_ERROR) {
|
|
135
|
-
debug('adduser: error on create user');
|
|
136
|
-
// With npm registering is the same as logging in,
|
|
137
|
-
// and npm accepts only an 409 error.
|
|
138
|
-
// So, changing status code here.
|
|
139
|
-
return next(
|
|
140
|
-
errorUtils.getCode(err.status, err.message) || errorUtils.getConflict(err.message)
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
return next(err);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const token =
|
|
147
|
-
name && password
|
|
148
|
-
? await getApiToken(auth, config, user as RemoteUser, password)
|
|
149
|
-
: undefined;
|
|
150
|
-
if (token) {
|
|
151
|
-
debug('adduser: new token %o', mask(token as string, 4));
|
|
152
|
-
}
|
|
153
|
-
if (!token) {
|
|
154
|
-
return next(errorUtils.getUnauthorized());
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
req.remote_user = user;
|
|
158
|
-
res.status(HTTP_STATUS.CREATED);
|
|
159
|
-
res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');
|
|
160
|
-
debug('adduser: user has been created');
|
|
161
|
-
return next({
|
|
162
|
-
ok: `user '${req.body.name}' created`,
|
|
163
|
-
token,
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
route.delete(
|
|
171
|
-
USER_API_ENDPOINTS.user_token,
|
|
172
|
-
function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
|
|
173
|
-
res.status(HTTP_STATUS.OK);
|
|
174
|
-
next({
|
|
175
|
-
ok: API_MESSAGE.LOGGED_OUT,
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
);
|
|
179
|
-
}
|
package/src/v1/profile.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { Response, Router } from 'express';
|
|
2
|
-
import _ from 'lodash';
|
|
3
|
-
|
|
4
|
-
import { Auth } from '@verdaccio/auth';
|
|
5
|
-
import {
|
|
6
|
-
API_ERROR,
|
|
7
|
-
APP_ERROR,
|
|
8
|
-
HTTP_STATUS,
|
|
9
|
-
SUPPORT_ERRORS,
|
|
10
|
-
errorUtils,
|
|
11
|
-
validatioUtils,
|
|
12
|
-
} from '@verdaccio/core';
|
|
13
|
-
import { PROFILE_API_ENDPOINTS } from '@verdaccio/middleware';
|
|
14
|
-
import { rateLimit } from '@verdaccio/middleware';
|
|
15
|
-
import { Config } from '@verdaccio/types';
|
|
16
|
-
|
|
17
|
-
import { $NextFunctionVer, $RequestExtend } from '../../types/custom';
|
|
18
|
-
|
|
19
|
-
export interface Profile {
|
|
20
|
-
tfa: boolean;
|
|
21
|
-
name: string;
|
|
22
|
-
email: string;
|
|
23
|
-
email_verified: boolean;
|
|
24
|
-
created: string;
|
|
25
|
-
updated: string;
|
|
26
|
-
cidr_whitelist: string[] | null;
|
|
27
|
-
fullname: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default function (route: Router, auth: Auth, config: Config): void {
|
|
31
|
-
function buildProfile(name: string): Profile {
|
|
32
|
-
return {
|
|
33
|
-
tfa: false,
|
|
34
|
-
name,
|
|
35
|
-
email: '',
|
|
36
|
-
email_verified: false,
|
|
37
|
-
created: '',
|
|
38
|
-
updated: '',
|
|
39
|
-
cidr_whitelist: null,
|
|
40
|
-
fullname: '',
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
route.get(
|
|
45
|
-
PROFILE_API_ENDPOINTS.get_profile,
|
|
46
|
-
rateLimit(config?.userRateLimit),
|
|
47
|
-
function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
|
|
48
|
-
if (_.isNil(req.remote_user.name) === false) {
|
|
49
|
-
return next(buildProfile(req.remote_user.name));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
res.status(HTTP_STATUS.UNAUTHORIZED);
|
|
53
|
-
return next({
|
|
54
|
-
message: API_ERROR.MUST_BE_LOGGED,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
route.post(
|
|
60
|
-
PROFILE_API_ENDPOINTS.get_profile,
|
|
61
|
-
rateLimit(config?.userRateLimit),
|
|
62
|
-
function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
|
|
63
|
-
if (_.isNil(req.remote_user.name)) {
|
|
64
|
-
res.status(HTTP_STATUS.UNAUTHORIZED);
|
|
65
|
-
return next({
|
|
66
|
-
message: API_ERROR.MUST_BE_LOGGED,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const { password, tfa } = req.body;
|
|
71
|
-
const { name } = req.remote_user;
|
|
72
|
-
|
|
73
|
-
if (_.isNil(password) === false) {
|
|
74
|
-
if (
|
|
75
|
-
validatioUtils.validatePassword(
|
|
76
|
-
password.new,
|
|
77
|
-
config?.serverSettings?.passwordValidationRegex
|
|
78
|
-
) === false
|
|
79
|
-
) {
|
|
80
|
-
/* eslint new-cap:off */
|
|
81
|
-
return next(errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT));
|
|
82
|
-
/* eslint new-cap:off */
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (_.isEmpty(password.old)) {
|
|
86
|
-
return next(errorUtils.getBadRequest('old password is required'));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
auth.changePassword(
|
|
90
|
-
name,
|
|
91
|
-
password.old,
|
|
92
|
-
password.new,
|
|
93
|
-
(err, isUpdated): $NextFunctionVer => {
|
|
94
|
-
if (_.isNull(err) === false) {
|
|
95
|
-
return next(errorUtils.getForbidden(err.message));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (isUpdated) {
|
|
99
|
-
return next(buildProfile(req.remote_user.name));
|
|
100
|
-
}
|
|
101
|
-
return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));
|
|
102
|
-
}
|
|
103
|
-
);
|
|
104
|
-
} else if (_.isNil(tfa) === false) {
|
|
105
|
-
return next(
|
|
106
|
-
errorUtils.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.TFA_DISABLED)
|
|
107
|
-
);
|
|
108
|
-
} else {
|
|
109
|
-
return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, APP_ERROR.PROFILE_ERROR));
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
);
|
|
113
|
-
}
|
package/src/v1/search.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import buildDebug from 'debug';
|
|
2
|
-
import _ from 'lodash';
|
|
3
|
-
|
|
4
|
-
import { Auth } from '@verdaccio/auth';
|
|
5
|
-
import { HTTP_STATUS, searchUtils } from '@verdaccio/core';
|
|
6
|
-
import { SEARCH_API_ENDPOINTS } from '@verdaccio/middleware';
|
|
7
|
-
import { Storage } from '@verdaccio/store';
|
|
8
|
-
import { Manifest } from '@verdaccio/types';
|
|
9
|
-
import { Logger } from '@verdaccio/types';
|
|
10
|
-
|
|
11
|
-
const debug = buildDebug('verdaccio:api:search');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Endpoint for npm search v1
|
|
15
|
-
* Empty value
|
|
16
|
-
* - {"objects":[],"total":0,"time":"Sun Jul 25 2021 14:09:11 GMT+0000 (Coordinated Universal Time)"}
|
|
17
|
-
* req: 'GET /-/v1/search?text=react&size=20&frpom=0&quality=0.65&popularity=0.98&maintenance=0.5'
|
|
18
|
-
*/
|
|
19
|
-
export default function (route, auth: Auth, storage: Storage, logger: Logger): void {
|
|
20
|
-
function checkAccess(pkg: any, auth: any, remoteUser): Promise<Manifest | null> {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
auth.allow_access({ packageName: pkg?.package?.name }, remoteUser, function (err, allowed) {
|
|
23
|
-
if (err) {
|
|
24
|
-
if (err.status && String(err.status).match(/^4\d\d$/)) {
|
|
25
|
-
// auth plugin returns 4xx user error,
|
|
26
|
-
// that's equivalent of !allowed basically
|
|
27
|
-
allowed = false;
|
|
28
|
-
return resolve(null);
|
|
29
|
-
} else {
|
|
30
|
-
reject(err);
|
|
31
|
-
}
|
|
32
|
-
} else {
|
|
33
|
-
return resolve(allowed ? pkg : null);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
route.get(SEARCH_API_ENDPOINTS.search, async (req, res, next) => {
|
|
40
|
-
const { query, url } = req;
|
|
41
|
-
let [size, from] = ['size', 'from'].map((k) => query[k]);
|
|
42
|
-
let data;
|
|
43
|
-
const abort = new AbortController();
|
|
44
|
-
|
|
45
|
-
req.socket.on('close', function () {
|
|
46
|
-
debug('search web aborted');
|
|
47
|
-
abort.abort();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
size = parseInt(size, 10) || 20;
|
|
51
|
-
from = parseInt(from, 10) || 0;
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
debug('storage search initiated');
|
|
55
|
-
data = await storage.search({
|
|
56
|
-
query,
|
|
57
|
-
url,
|
|
58
|
-
abort,
|
|
59
|
-
});
|
|
60
|
-
debug('storage items tota: %o', data.length);
|
|
61
|
-
const checkAccessPromises: searchUtils.SearchItemPkg[] = await Promise.all(
|
|
62
|
-
data.map((pkgItem) => {
|
|
63
|
-
return checkAccess(pkgItem, auth, req.remote_user);
|
|
64
|
-
})
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const final: searchUtils.SearchItemPkg[] = checkAccessPromises
|
|
68
|
-
.filter((i) => !_.isNull(i))
|
|
69
|
-
.slice(from, size);
|
|
70
|
-
logger.debug(`search results ${final?.length}`);
|
|
71
|
-
|
|
72
|
-
const response: searchUtils.SearchResults = {
|
|
73
|
-
objects: final,
|
|
74
|
-
total: final.length,
|
|
75
|
-
time: new Date().toUTCString(),
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
res.status(HTTP_STATUS.OK).json(response);
|
|
79
|
-
} catch (error) {
|
|
80
|
-
logger.error({ error }, 'search endpoint has failed @{error.message}');
|
|
81
|
-
next(next);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
package/src/v1/token.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Response, Router } from 'express';
|
|
2
|
-
import _ from 'lodash';
|
|
3
|
-
|
|
4
|
-
import { getApiToken } from '@verdaccio/auth';
|
|
5
|
-
import { Auth } from '@verdaccio/auth';
|
|
6
|
-
import { HEADERS, HTTP_STATUS, SUPPORT_ERRORS, errorUtils } from '@verdaccio/core';
|
|
7
|
-
import { rateLimit } from '@verdaccio/middleware';
|
|
8
|
-
import { TOKEN_API_ENDPOINTS } from '@verdaccio/middleware';
|
|
9
|
-
import { Storage } from '@verdaccio/store';
|
|
10
|
-
import { Config, RemoteUser, Token } from '@verdaccio/types';
|
|
11
|
-
import { Logger } from '@verdaccio/types';
|
|
12
|
-
import { mask, stringToMD5 } from '@verdaccio/utils';
|
|
13
|
-
|
|
14
|
-
import { $NextFunctionVer, $RequestExtend } from '../../types/custom';
|
|
15
|
-
|
|
16
|
-
export type NormalizeToken = Token & {
|
|
17
|
-
created: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
function normalizeToken(token: Token): NormalizeToken {
|
|
21
|
-
return {
|
|
22
|
-
...token,
|
|
23
|
-
created: new Date(token.created).toISOString(),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// https://github.com/npm/npm-profile/blob/latest/lib/index.js
|
|
28
|
-
export default function (
|
|
29
|
-
route: Router,
|
|
30
|
-
auth: Auth,
|
|
31
|
-
storage: Storage,
|
|
32
|
-
config: Config,
|
|
33
|
-
logger: Logger
|
|
34
|
-
): void {
|
|
35
|
-
route.get(
|
|
36
|
-
TOKEN_API_ENDPOINTS.get_tokens,
|
|
37
|
-
rateLimit(config?.userRateLimit),
|
|
38
|
-
async function (req: $RequestExtend, res: Response, next: $NextFunctionVer) {
|
|
39
|
-
const { name } = req.remote_user;
|
|
40
|
-
|
|
41
|
-
if (_.isNil(name) === false) {
|
|
42
|
-
try {
|
|
43
|
-
const tokens = await storage.readTokens({ user: name });
|
|
44
|
-
const totalTokens = tokens.length;
|
|
45
|
-
logger.debug({ totalTokens }, 'token list retrieved: @{totalTokens}');
|
|
46
|
-
|
|
47
|
-
res.status(HTTP_STATUS.OK);
|
|
48
|
-
return next({
|
|
49
|
-
objects: tokens.map(normalizeToken),
|
|
50
|
-
urls: {
|
|
51
|
-
next: '', // TODO: pagination?
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
} catch (error: any) {
|
|
55
|
-
logger.error({ error: error.msg }, 'token list has failed: @{error}');
|
|
56
|
-
return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return next(errorUtils.getUnauthorized());
|
|
60
|
-
}
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
route.post(
|
|
64
|
-
TOKEN_API_ENDPOINTS.get_tokens,
|
|
65
|
-
rateLimit(config?.userRateLimit),
|
|
66
|
-
function (req: $RequestExtend, res: Response, next: $NextFunctionVer) {
|
|
67
|
-
const { password, readonly, cidr_whitelist } = req.body;
|
|
68
|
-
const { name } = req.remote_user;
|
|
69
|
-
|
|
70
|
-
if (!_.isBoolean(readonly) || !_.isArray(cidr_whitelist)) {
|
|
71
|
-
return next(errorUtils.getCode(HTTP_STATUS.BAD_DATA, SUPPORT_ERRORS.PARAMETERS_NOT_VALID));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
auth.authenticate(name, password, async (err, user?: RemoteUser) => {
|
|
75
|
-
if (err) {
|
|
76
|
-
const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR;
|
|
77
|
-
return next(errorUtils.getCode(errorCode, err.message));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
req.remote_user = user;
|
|
81
|
-
|
|
82
|
-
if (!_.isFunction(storage.saveToken)) {
|
|
83
|
-
return next(
|
|
84
|
-
errorUtils.getCode(HTTP_STATUS.NOT_IMPLEMENTED, SUPPORT_ERRORS.STORAGE_NOT_IMPLEMENT)
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const token = await getApiToken(auth, config, user as RemoteUser, password);
|
|
90
|
-
if (!token) {
|
|
91
|
-
throw errorUtils.getInternalError();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const key = stringToMD5(token);
|
|
95
|
-
// TODO: use a utility here
|
|
96
|
-
const maskedToken = mask(token, 5);
|
|
97
|
-
const created = new Date().getTime();
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* cidr_whitelist: is not being used, we pass it through
|
|
101
|
-
* token: we do not store the real token (it is generated once and retrieved
|
|
102
|
-
* to the user), just a mask of it.
|
|
103
|
-
*/
|
|
104
|
-
const saveToken: Token = {
|
|
105
|
-
user: name,
|
|
106
|
-
token: maskedToken,
|
|
107
|
-
key,
|
|
108
|
-
cidr: cidr_whitelist,
|
|
109
|
-
readonly,
|
|
110
|
-
created,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
await storage.saveToken(saveToken);
|
|
114
|
-
logger.debug({ key, name }, 'token @{key} was created for user @{name}');
|
|
115
|
-
res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');
|
|
116
|
-
return next(
|
|
117
|
-
normalizeToken({
|
|
118
|
-
token,
|
|
119
|
-
user: name,
|
|
120
|
-
key: saveToken.key,
|
|
121
|
-
cidr: cidr_whitelist,
|
|
122
|
-
readonly,
|
|
123
|
-
created: saveToken.created,
|
|
124
|
-
})
|
|
125
|
-
);
|
|
126
|
-
} catch (error: any) {
|
|
127
|
-
logger.error({ error: error.msg }, 'token creation has failed: @{error}');
|
|
128
|
-
return next(errorUtils.getInternalError(error.message));
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
route.delete(
|
|
135
|
-
TOKEN_API_ENDPOINTS.delete_token,
|
|
136
|
-
rateLimit(config?.userRateLimit),
|
|
137
|
-
async (req: $RequestExtend, res: Response, next: $NextFunctionVer) => {
|
|
138
|
-
const {
|
|
139
|
-
params: { tokenKey },
|
|
140
|
-
} = req;
|
|
141
|
-
const { name } = req.remote_user;
|
|
142
|
-
|
|
143
|
-
if (_.isNil(name) === false) {
|
|
144
|
-
logger.debug({ name }, '@{name} has requested remove a token');
|
|
145
|
-
try {
|
|
146
|
-
await storage.deleteToken(name, tokenKey);
|
|
147
|
-
logger.info({ tokenKey, name }, 'token id @{tokenKey} was revoked for user @{name}');
|
|
148
|
-
return next({});
|
|
149
|
-
} catch (error: any) {
|
|
150
|
-
logger.error({ error: error.msg }, 'token creation has failed: @{error}');
|
|
151
|
-
return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, error.message));
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return next(errorUtils.getUnauthorized());
|
|
155
|
-
}
|
|
156
|
-
);
|
|
157
|
-
}
|
package/src/whoami.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import buildDebug from 'debug';
|
|
2
|
-
import { Response, Router } from 'express';
|
|
3
|
-
|
|
4
|
-
import { errorUtils } from '@verdaccio/core';
|
|
5
|
-
import { USER_API_ENDPOINTS } from '@verdaccio/middleware';
|
|
6
|
-
|
|
7
|
-
import { $NextFunctionVer, $RequestExtend } from '../types/custom';
|
|
8
|
-
|
|
9
|
-
const debug = buildDebug('verdaccio:api:user');
|
|
10
|
-
|
|
11
|
-
export default function (route: Router): void {
|
|
12
|
-
route.get(
|
|
13
|
-
USER_API_ENDPOINTS.whoami,
|
|
14
|
-
(req: $RequestExtend, _res: Response, next: $NextFunctionVer): any => {
|
|
15
|
-
// remote_user is set by the auth middleware
|
|
16
|
-
const username = req?.remote_user?.name;
|
|
17
|
-
if (!username) {
|
|
18
|
-
debug('whoami: user not found');
|
|
19
|
-
return next(errorUtils.getUnauthorized('Unauthorized'));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
debug('whoami: response %o', username);
|
|
23
|
-
return next({ username: username });
|
|
24
|
-
}
|
|
25
|
-
);
|
|
26
|
-
}
|