@verdaccio/api 8.1.0-next-8.4 → 8.1.0-next-8.5

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 CHANGED
@@ -1,5 +1,30 @@
1
1
  # @verdaccio/api
2
2
 
3
+ ## 8.1.0-next-8.5
4
+
5
+ ### Patch Changes
6
+
7
+ - eca6259: fix: E409 username is already registered (adduser)
8
+ - 5cbee6f: fix: unpublish a package on storage package
9
+ - 6e344d0: chore(api): fix void return for some tests
10
+ - Updated dependencies [ba71932]
11
+ - Updated dependencies [64a7fc0]
12
+ - Updated dependencies [9041b0f]
13
+ - Updated dependencies [eca6259]
14
+ - Updated dependencies [4adaa83]
15
+ - Updated dependencies [80e4cb8]
16
+ - Updated dependencies [5cbee6f]
17
+ - Updated dependencies [538bb8f]
18
+ - Updated dependencies [a049bba]
19
+ - Updated dependencies [3967a52]
20
+ - @verdaccio/config@8.0.0-next-8.5
21
+ - @verdaccio/core@8.0.0-next-8.5
22
+ - @verdaccio/store@8.0.0-next-8.5
23
+ - @verdaccio/auth@8.0.0-next-8.5
24
+ - @verdaccio/logger@8.0.0-next-8.5
25
+ - @verdaccio/middleware@8.0.0-next-8.5
26
+ - @verdaccio/utils@8.1.0-next-8.5
27
+
3
28
  ## 8.1.0-next-8.4
4
29
 
5
30
  ### Patch Changes
package/build/package.js CHANGED
@@ -16,12 +16,23 @@ function _default(route, auth, storage, logger) {
16
16
  afterAll: (a, b) => logger.trace(a, b)
17
17
  });
18
18
  route.get('/:package/:version?', can('access'), async function (req, _res, next) {
19
- debug('init package by version');
19
+ debug('get package by version');
20
20
  const name = req.params.package;
21
21
  let version = req.params.version;
22
22
  const write = req.query.write === 'true';
23
23
  const username = req?.remote_user?.name;
24
24
  const abbreviated = _core.stringUtils.getByQualityPriorityValue(req.get('Accept')) === _store.Storage.ABBREVIATED_HEADER;
25
+ if (debug.enabled) {
26
+ debug('is write %o', write);
27
+ debug('is abbreviated %o', abbreviated);
28
+ debug('package %o', name);
29
+ debug('version %o', version);
30
+ debug('username %o', username);
31
+ debug('remote address %o', req.socket.remoteAddress);
32
+ debug('host %o', req.host);
33
+ debug('protocol %o', req.protocol);
34
+ debug('url %o', req.url);
35
+ }
25
36
  const requestOptions = {
26
37
  protocol: req.protocol,
27
38
  headers: req.headers,
@@ -40,8 +51,10 @@ function _default(route, auth, storage, logger) {
40
51
  requestOptions
41
52
  });
42
53
  if (abbreviated) {
54
+ debug('abbreviated response');
43
55
  _res.setHeader(_core.HEADER_TYPE.CONTENT_TYPE, _core.HEADERS.JSON_INSTALL_CHARSET);
44
56
  } else {
57
+ debug('full response');
45
58
  _res.setHeader(_core.HEADER_TYPE.CONTENT_TYPE, _core.HEADERS.JSON);
46
59
  }
47
60
  next(manifest);
@@ -56,15 +69,18 @@ function _default(route, auth, storage, logger) {
56
69
  } = req.params;
57
70
  const abort = new AbortController();
58
71
  try {
72
+ debug('downloading tarball %o', filename);
59
73
  const stream = await storage.getTarball(pkgName, filename, {
60
74
  signal: abort.signal
61
75
  // TODO: review why this param
62
76
  // enableRemote: true,
63
77
  });
64
78
  stream.on('content-length', size => {
79
+ debug('tarball size %o', size);
65
80
  res.header(_core.HEADER_TYPE.CONTENT_LENGTH, size);
66
81
  });
67
82
  stream.once('error', err => {
83
+ debug('error on download tarball %o', err);
68
84
  res.locals.report_error(err);
69
85
  next(err);
70
86
  });
@@ -75,7 +91,6 @@ function _default(route, auth, storage, logger) {
75
91
  res.header(_core.HEADERS.CONTENT_TYPE, _core.HEADERS.OCTET_STREAM);
76
92
  stream.pipe(res);
77
93
  } catch (err) {
78
- // console.log('catch API error request', err);
79
94
  res.locals.report_error(err);
80
95
  next(err);
81
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":["_debug","_interopRequireDefault","require","_core","_middleware","_store","e","__esModule","default","debug","buildDebug","_default","route","auth","storage","logger","can","allow","beforeAll","a","b","trace","afterAll","get","req","_res","next","name","params","package","version","write","query","username","remote_user","abbreviated","stringUtils","getByQualityPriorityValue","Storage","ABBREVIATED_HEADER","requestOptions","protocol","headers","host","remoteAddress","socket","byPassCache","manifest","getPackageByOptions","uplinksLook","setHeader","HEADER_TYPE","CONTENT_TYPE","HEADERS","JSON_INSTALL_CHARSET","JSON","err","res","pkgName","filename","abort","AbortController","stream","getTarball","signal","on","size","header","CONTENT_LENGTH","once","locals","report_error","url","OCTET_STREAM","pipe"],"sources":["../src/package.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\n\nimport { Auth } from '@verdaccio/auth';\nimport { HEADERS, HEADER_TYPE, stringUtils } from '@verdaccio/core';\nimport { allow } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\nimport { Logger } from '@verdaccio/types';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\nconst debug = buildDebug('verdaccio:api:package');\n\nexport default function (route: Router, auth: Auth, storage: Storage, logger: Logger): void {\n const can = allow(auth, {\n beforeAll: (a, b) => logger.trace(a, b),\n afterAll: (a, b) => logger.trace(a, b),\n });\n route.get(\n '/:package/:version?',\n can('access'),\n async function (\n req: $RequestExtend,\n _res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n debug('init package by version');\n const name = req.params.package;\n let version = req.params.version;\n const write = req.query.write === 'true';\n const username = req?.remote_user?.name;\n const abbreviated =\n stringUtils.getByQualityPriorityValue(req.get('Accept')) === Storage.ABBREVIATED_HEADER;\n const requestOptions = {\n protocol: req.protocol,\n headers: req.headers as any,\n // FIXME: if we migrate to req.hostname, the port is not longer included.\n host: req.host,\n remoteAddress: req.socket.remoteAddress,\n byPassCache: write,\n username,\n };\n\n try {\n const manifest = await storage.getPackageByOptions({\n name,\n uplinksLook: true,\n abbreviated,\n version,\n requestOptions,\n });\n if (abbreviated) {\n _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET);\n } else {\n _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);\n }\n\n next(manifest);\n } catch (err) {\n next(err);\n }\n }\n );\n\n route.get(\n '/:package/-/:filename',\n can('access'),\n async function (req: $RequestExtend, res: $ResponseExtend, next): Promise<void> {\n const { package: pkgName, filename } = req.params;\n const abort = new AbortController();\n try {\n const stream = (await storage.getTarball(pkgName, filename, {\n signal: abort.signal,\n // TODO: review why this param\n // enableRemote: true,\n })) as any;\n\n stream.on('content-length', (size) => {\n res.header(HEADER_TYPE.CONTENT_LENGTH, size);\n });\n\n stream.once('error', (err) => {\n res.locals.report_error(err);\n next(err);\n });\n\n req.on('abort', () => {\n debug('request aborted for %o', req.url);\n abort.abort();\n });\n\n res.header(HEADERS.CONTENT_TYPE, HEADERS.OCTET_STREAM);\n stream.pipe(res);\n } catch (err: any) {\n // console.log('catch API error request', err);\n res.locals.report_error(err);\n next(err);\n }\n }\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"package.js","names":["_debug","_interopRequireDefault","require","_core","_middleware","_store","e","__esModule","default","debug","buildDebug","_default","route","auth","storage","logger","can","allow","beforeAll","a","b","trace","afterAll","get","req","_res","next","name","params","package","version","write","query","username","remote_user","abbreviated","stringUtils","getByQualityPriorityValue","Storage","ABBREVIATED_HEADER","enabled","socket","remoteAddress","host","protocol","url","requestOptions","headers","byPassCache","manifest","getPackageByOptions","uplinksLook","setHeader","HEADER_TYPE","CONTENT_TYPE","HEADERS","JSON_INSTALL_CHARSET","JSON","err","res","pkgName","filename","abort","AbortController","stream","getTarball","signal","on","size","header","CONTENT_LENGTH","once","locals","report_error","OCTET_STREAM","pipe"],"sources":["../src/package.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\n\nimport { Auth } from '@verdaccio/auth';\nimport { HEADERS, HEADER_TYPE, stringUtils } from '@verdaccio/core';\nimport { allow } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\nimport { Logger } from '@verdaccio/types';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\nconst debug = buildDebug('verdaccio:api:package');\n\nexport default function (route: Router, auth: Auth, storage: Storage, logger: Logger): void {\n const can = allow(auth, {\n beforeAll: (a, b) => logger.trace(a, b),\n afterAll: (a, b) => logger.trace(a, b),\n });\n route.get(\n '/:package/:version?',\n can('access'),\n async function (\n req: $RequestExtend,\n _res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n debug('get package by version');\n const name = req.params.package;\n let version = req.params.version;\n const write = req.query.write === 'true';\n const username = req?.remote_user?.name;\n const abbreviated =\n stringUtils.getByQualityPriorityValue(req.get('Accept')) === Storage.ABBREVIATED_HEADER;\n if (debug.enabled) {\n debug('is write %o', write);\n debug('is abbreviated %o', abbreviated);\n debug('package %o', name);\n debug('version %o', version);\n debug('username %o', username);\n debug('remote address %o', req.socket.remoteAddress);\n debug('host %o', req.host);\n debug('protocol %o', req.protocol);\n debug('url %o', req.url);\n }\n const requestOptions = {\n protocol: req.protocol,\n headers: req.headers as any,\n // FIXME: if we migrate to req.hostname, the port is not longer included.\n host: req.host,\n remoteAddress: req.socket.remoteAddress,\n byPassCache: write,\n username,\n };\n\n try {\n const manifest = await storage.getPackageByOptions({\n name,\n uplinksLook: true,\n abbreviated,\n version,\n requestOptions,\n });\n if (abbreviated) {\n debug('abbreviated response');\n _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET);\n } else {\n debug('full response');\n _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);\n }\n\n next(manifest);\n } catch (err) {\n next(err);\n }\n }\n );\n\n route.get(\n '/:package/-/:filename',\n can('access'),\n async function (req: $RequestExtend, res: $ResponseExtend, next): Promise<void> {\n const { package: pkgName, filename } = req.params;\n const abort = new AbortController();\n try {\n debug('downloading tarball %o', filename);\n const stream = (await storage.getTarball(pkgName, filename, {\n signal: abort.signal,\n // TODO: review why this param\n // enableRemote: true,\n })) as any;\n\n stream.on('content-length', (size) => {\n debug('tarball size %o', size);\n res.header(HEADER_TYPE.CONTENT_LENGTH, size);\n });\n\n stream.once('error', (err) => {\n debug('error on download tarball %o', err);\n res.locals.report_error(err);\n next(err);\n });\n\n req.on('abort', () => {\n debug('request aborted for %o', req.url);\n abort.abort();\n });\n\n res.header(HEADERS.CONTENT_TYPE, HEADERS.OCTET_STREAM);\n stream.pipe(res);\n } catch (err: any) {\n res.locals.report_error(err);\n next(err);\n }\n }\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -98,4 +98,4 @@ import { Logger } from '@verdaccio/types';
98
98
  *
99
99
  */
100
100
  export default function publish(router: Router, auth: Auth, storage: Storage, logger: Logger): void;
101
- export declare function publishPackage(storage: Storage, logger: Logger): any;
101
+ export declare function publishPackage(storage: Storage, logger: Logger, origin: string): any;
package/build/publish.js CHANGED
@@ -73,7 +73,7 @@ const debug = (0, _debug.default)('verdaccio:api:publish');
73
73
  * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1601ms
74
74
  * Remove the tarball
75
75
  * npm http fetch DELETE 201 http://localhost:4873/custom-name/-/test1-1.0.3.tgz/-rev/16-e11c8db282b2d992 19ms
76
- *
76
+ *
77
77
  * 3. Star a package
78
78
  *
79
79
  * Permissions: staring a package depends of the publish and unpublish permissions, there is no
@@ -94,7 +94,7 @@ const debug = (0, _debug.default)('verdaccio:api:publish');
94
94
  * 4. Change owners of a package
95
95
  *
96
96
  * Similar to staring a package, changing owners (maintainers) of a package uses the publish
97
- * endpoint.
97
+ * endpoint.
98
98
  *
99
99
  * The body includes a list of the new owners with the following format
100
100
  *
@@ -114,15 +114,24 @@ function publish(router, auth, storage, logger) {
114
114
  beforeAll: (a, b) => logger.trace(a, b),
115
115
  afterAll: (a, b) => logger.trace(a, b)
116
116
  });
117
- router.put('/:package', can('publish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackage(storage, logger));
118
- router.put('/:package/-rev/:revision', can('unpublish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackage(storage, logger));
117
+ router.put('/:package', can('publish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackage(storage, logger, 'publish one version'));
118
+ router.put('/:package/-rev/:revision', can('unpublish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackage(storage, logger, 'publish with revision'));
119
119
 
120
120
  /**
121
121
  * Un-publishing an entire package.
122
122
  *
123
- * This scenario happens when the first call detect there is only one version remaining
124
- * in the metadata, then the client decides to DELETE the resource
123
+ * This scenario happens when any of these scenarios happens:
124
+ * - the first call detect there is only one version remaining
125
+ * - no version is specified in the unpublish call
126
+ * - all versions are removed npm unpublish package@*
127
+ * - there is no versions on the metadata
128
+
129
+ * then the client decides to DELETE the resource
130
+ * Example:
131
+ * Get fresh manifest (write=true is a flag to get the latest revision)
125
132
  * npm http fetch GET 304 http://localhost:4873/package-name?write=true 1076ms (from cache)
133
+ * Send request to delete the package, this includes the revision number that must match
134
+ * and the package name, it will delete the entire package and all tarballs (or tarball depends the scenario)
126
135
  * npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms
127
136
  */
128
137
  router.delete('/:package/-rev/:revision', can('unpublish'), async function (req, res, next) {
@@ -176,13 +185,19 @@ function publish(router, auth, storage, logger) {
176
185
  }
177
186
  });
178
187
  }
179
- function publishPackage(storage, logger) {
188
+ function publishPackage(storage, logger, origin) {
180
189
  return async function (req, res, next) {
190
+ debug(origin);
181
191
  const ac = new AbortController();
182
192
  const packageName = req.params.package;
183
193
  const {
184
194
  revision
185
195
  } = req.params;
196
+ debug('publishing package %s', packageName);
197
+ debug('revision %s', revision);
198
+ if (debug.enabled) {
199
+ debug('body %o', req.body);
200
+ }
186
201
  const metadata = req.body;
187
202
  const username = req?.remote_user?.name;
188
203
  debug('publishing package %o for user %o', packageName, username);
@@ -203,6 +218,7 @@ function publishPackage(storage, logger) {
203
218
  },
204
219
  uplinksLook: false
205
220
  });
221
+ debug('package %s published', packageName);
206
222
  res.status(_core.HTTP_STATUS.CREATED);
207
223
  return next({
208
224
  success: true,
@@ -1 +1 @@
1
- {"version":3,"file":"publish.js","names":["_debug","_interopRequireDefault","require","_mime","_core","_middleware","e","__esModule","default","debug","buildDebug","publish","router","auth","storage","logger","can","allow","beforeAll","a","b","trace","afterAll","put","media","mime","getType","expectJson","publishPackage","delete","req","res","next","packageName","params","package","rev","revision","username","remote_user","name","removePackage","status","HTTP_STATUS","CREATED","ok","API_MESSAGE","PKG_REMOVED","err","filename","removeTarball","TARBALL_REMOVED","ac","AbortController","metadata","body","message","updateManifest","signal","requestOptions","host","hostname","protocol","headers","uplinksLook","success"],"sources":["../src/publish.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport mime from 'mime';\n\nimport { Auth } from '@verdaccio/auth';\nimport { API_MESSAGE, HTTP_STATUS } from '@verdaccio/core';\nimport { allow, expectJson, media } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\nimport { Logger } from '@verdaccio/types';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\n// import star from './star';\n\nconst debug = buildDebug('verdaccio:api:publish');\n\n/**\n * Publish a package / update package / un/start a package\n *\n * There are multiples scenarios here to be considered:\n *\n * 1. Publish scenario\n *\n * Publish a package consist of at least 1 step (PUT) with a metadata payload.\n * When a package is published, an _attachment property is present that contains the data\n * of the tarball.\n *\n * Example flow of publish.\n *\n * npm http fetch PUT 201 http://localhost:4873/@scope%2ftest1 9627ms\n npm info lifecycle @scope/test1@1.0.1~publish: @scope/test1@1.0.1\n npm info lifecycle @scope/test1@1.0.1~postpublish: @scope/test1@1.0.1\n + @scope/test1@1.0.1\n npm verb exit [ 0, true ]\n *\n *\n * 2. Unpublish scenario\n *\n * Unpublish consist in 3 steps.\n * 1. Try to fetch metadata -> if it fails, return 404\n * 2. Compute metadata locally (client side) and send a mutate payload excluding the version to\n * be unpublished\n * eg: if metadata reflects 1.0.1, 1.0.2 and 1.0.3, the computed metadata won't include 1.0.3.\n * 3. Once the second step has been successfully finished, delete the tarball.\n *\n * All these steps are consecutive and required, there is no transacions here, if step 3 fails,\n * metadata might get corrupted.\n *\n * Note the unpublish call will suffix in the url a /-rev/14-5d500cfce92f90fd revision number,\n * this not\n * used internally.\n *\n *\n * Example flow of unpublish.\n *\n * There are two possible flows:\n *\n * - Remove all packages (entirely)\n * eg: npm unpublish package-name@* --force\n * eg: npm unpublish package-name --force\n *\n * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1680ms\n * npm http fetch DELETE 201 http://localhost:4873/custom-name/-/test1-1.0.3.tgz/-rev/16-e11c8db282b2d992 19ms\n *\n * - Remove a specific version\n * eg: npm unpublish package-name@1.0.0 --force\n *\n * Get fresh manifest\n * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1680ms\n * Update manifest without the version to be unpublished\n * npm http fetch PUT 201 http://localhost:4873/custom-name/-rev/14-5d500cfce92f90fd 956606ms\n * Get fresh manifest (revision should be different)\n * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1601ms\n * Remove the tarball\n * npm http fetch DELETE 201 http://localhost:4873/custom-name/-/test1-1.0.3.tgz/-rev/16-e11c8db282b2d992 19ms\n * \n * 3. Star a package\n *\n * Permissions: staring a package depends of the publish and unpublish permissions, there is no\n * specific flag for star or unstar.\n * The URL for star is similar to the unpublish (change package format)\n *\n * npm has no endpoint for staring a package, rather mutate the metadata and acts as, the difference\n * is the users property which is part of the payload and the body only includes\n *\n * {\n\t\t \"_id\": pkgName,\n\t \t\"_rev\": \"3-b0cdaefc9bdb77c8\",\n\t\t \"users\": {\n\t\t [username]: boolean value (true, false)\n\t\t }\n\t }\n *\n * 4. Change owners of a package\n *\n * Similar to staring a package, changing owners (maintainers) of a package uses the publish\n * endpoint. \n *\n * The body includes a list of the new owners with the following format\n *\n * {\n\t\t \"_id\": pkgName,\n\t \t\"_rev\": \"4-b0cdaefc9bdb77c8\",\n\t\t \"maintainers\": [\n { \"name\": \"first owner\", \"email\": \"me@verdaccio.org\" },\n { \"name\": \"second owner\", \"email\": \"you@verdaccio.org\" },\n ...\n\t\t ]\n\t }\n *\n */\nexport default function publish(\n router: Router,\n auth: Auth,\n storage: Storage,\n logger: Logger\n): void {\n const can = allow(auth, {\n beforeAll: (a, b) => logger.trace(a, b),\n afterAll: (a, b) => logger.trace(a, b),\n });\n router.put(\n '/:package',\n can('publish'),\n media(mime.getType('json')),\n expectJson,\n publishPackage(storage, logger)\n );\n\n router.put(\n '/:package/-rev/:revision',\n can('unpublish'),\n media(mime.getType('json')),\n expectJson,\n publishPackage(storage, logger)\n );\n\n /**\n * Un-publishing an entire package.\n *\n * This scenario happens when the first call detect there is only one version remaining\n * in the metadata, then the client decides to DELETE the resource\n * npm http fetch GET 304 http://localhost:4873/package-name?write=true 1076ms (from cache)\n * npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms\n */\n router.delete(\n '/:package/-rev/:revision',\n can('unpublish'),\n async function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {\n const packageName = req.params.package;\n const rev = req.params.revision;\n const username = req?.remote_user?.name;\n\n logger.debug({ packageName }, `unpublishing @{packageName}`);\n try {\n await storage.removePackage(packageName, rev, username);\n debug('package %s unpublished', packageName);\n res.status(HTTP_STATUS.CREATED);\n return next({ ok: API_MESSAGE.PKG_REMOVED });\n } catch (err) {\n return next(err);\n }\n }\n );\n\n /*\n Remove a tarball, this happens when npm unpublish a package unique version.\n npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms\n */\n router.delete(\n '/:package/-/:filename/-rev/:revision',\n can('unpublish'),\n can('publish'),\n async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n const packageName = req.params.package;\n const { filename, revision } = req.params;\n const username = req?.remote_user?.name;\n\n logger.debug(\n { packageName, filename, revision },\n `removing a tarball for @{packageName}-@{tarballName}-@{revision}`\n );\n try {\n await storage.removeTarball(packageName, filename, revision, username);\n res.status(HTTP_STATUS.CREATED);\n\n logger.debug(\n { packageName, filename, revision },\n `success remove tarball for @{packageName}-@{tarballName}-@{revision}`\n );\n return next({ ok: API_MESSAGE.TARBALL_REMOVED });\n } catch (err) {\n return next(err);\n }\n }\n );\n}\n\nexport function publishPackage(storage: Storage, logger: Logger): any {\n return async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n const ac = new AbortController();\n const packageName = req.params.package;\n const { revision } = req.params;\n const metadata = req.body;\n const username = req?.remote_user?.name;\n\n debug('publishing package %o for user %o', packageName, username);\n logger.debug(\n { packageName, username },\n 'publishing package @{packageName} for user @{username}'\n );\n\n try {\n const message = await storage.updateManifest(metadata, {\n name: packageName,\n revision,\n signal: ac.signal,\n requestOptions: {\n host: req.hostname,\n protocol: req.protocol,\n headers: req.headers as { [key: string]: string },\n username,\n },\n uplinksLook: false,\n });\n\n res.status(HTTP_STATUS.CREATED);\n\n return next({\n success: true,\n ok: message,\n });\n } catch (err: any) {\n // TODO: review if we need the abort controller here\n next(err);\n }\n };\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,KAAA,GAAAF,sBAAA,CAAAC,OAAA;AAGA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,WAAA,GAAAH,OAAA;AAAiE,SAAAD,uBAAAK,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAMjE;;AAEA,MAAMG,KAAK,GAAG,IAAAC,cAAU,EAAC,uBAAuB,CAAC;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,SAASC,OAAOA,CAC7BC,MAAc,EACdC,IAAU,EACVC,OAAgB,EAChBC,MAAc,EACR;EACN,MAAMC,GAAG,GAAG,IAAAC,iBAAK,EAACJ,IAAI,EAAE;IACtBK,SAAS,EAAEA,CAACC,CAAC,EAAEC,CAAC,KAAKL,MAAM,CAACM,KAAK,CAACF,CAAC,EAAEC,CAAC,CAAC;IACvCE,QAAQ,EAAEA,CAACH,CAAC,EAAEC,CAAC,KAAKL,MAAM,CAACM,KAAK,CAACF,CAAC,EAAEC,CAAC;EACvC,CAAC,CAAC;EACFR,MAAM,CAACW,GAAG,CACR,WAAW,EACXP,GAAG,CAAC,SAAS,CAAC,EACd,IAAAQ,iBAAK,EAACC,aAAI,CAACC,OAAO,CAAC,MAAM,CAAC,CAAC,EAC3BC,sBAAU,E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","ignoreList":[]}
1
+ {"version":3,"file":"publish.js","names":["_debug","_interopRequireDefault","require","_mime","_core","_middleware","e","__esModule","default","debug","buildDebug","publish","router","auth","storage","logger","can","allow","beforeAll","a","b","trace","afterAll","put","media","mime","getType","expectJson","publishPackage","delete","req","res","next","packageName","params","package","rev","revision","username","remote_user","name","removePackage","status","HTTP_STATUS","CREATED","ok","API_MESSAGE","PKG_REMOVED","err","filename","removeTarball","TARBALL_REMOVED","origin","ac","AbortController","enabled","body","metadata","message","updateManifest","signal","requestOptions","host","hostname","protocol","headers","uplinksLook","success"],"sources":["../src/publish.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport mime from 'mime';\n\nimport { Auth } from '@verdaccio/auth';\nimport { API_MESSAGE, HTTP_STATUS } from '@verdaccio/core';\nimport { allow, expectJson, media } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\nimport { Logger } from '@verdaccio/types';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\n// import star from './star';\n\nconst debug = buildDebug('verdaccio:api:publish');\n\n/**\n * Publish a package / update package / un/start a package\n *\n * There are multiples scenarios here to be considered:\n *\n * 1. Publish scenario\n *\n * Publish a package consist of at least 1 step (PUT) with a metadata payload.\n * When a package is published, an _attachment property is present that contains the data\n * of the tarball.\n *\n * Example flow of publish.\n *\n * npm http fetch PUT 201 http://localhost:4873/@scope%2ftest1 9627ms\n npm info lifecycle @scope/test1@1.0.1~publish: @scope/test1@1.0.1\n npm info lifecycle @scope/test1@1.0.1~postpublish: @scope/test1@1.0.1\n + @scope/test1@1.0.1\n npm verb exit [ 0, true ]\n *\n *\n * 2. Unpublish scenario\n *\n * Unpublish consist in 3 steps.\n * 1. Try to fetch metadata -> if it fails, return 404\n * 2. Compute metadata locally (client side) and send a mutate payload excluding the version to\n * be unpublished\n * eg: if metadata reflects 1.0.1, 1.0.2 and 1.0.3, the computed metadata won't include 1.0.3.\n * 3. Once the second step has been successfully finished, delete the tarball.\n *\n * All these steps are consecutive and required, there is no transacions here, if step 3 fails,\n * metadata might get corrupted.\n *\n * Note the unpublish call will suffix in the url a /-rev/14-5d500cfce92f90fd revision number,\n * this not\n * used internally.\n *\n *\n * Example flow of unpublish.\n *\n * There are two possible flows:\n *\n * - Remove all packages (entirely)\n * eg: npm unpublish package-name@* --force\n * eg: npm unpublish package-name --force\n *\n * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1680ms\n * npm http fetch DELETE 201 http://localhost:4873/custom-name/-/test1-1.0.3.tgz/-rev/16-e11c8db282b2d992 19ms\n *\n * - Remove a specific version\n * eg: npm unpublish package-name@1.0.0 --force\n *\n * Get fresh manifest\n * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1680ms\n * Update manifest without the version to be unpublished\n * npm http fetch PUT 201 http://localhost:4873/custom-name/-rev/14-5d500cfce92f90fd 956606ms\n * Get fresh manifest (revision should be different)\n * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1601ms\n * Remove the tarball\n * npm http fetch DELETE 201 http://localhost:4873/custom-name/-/test1-1.0.3.tgz/-rev/16-e11c8db282b2d992 19ms\n *\n * 3. Star a package\n *\n * Permissions: staring a package depends of the publish and unpublish permissions, there is no\n * specific flag for star or unstar.\n * The URL for star is similar to the unpublish (change package format)\n *\n * npm has no endpoint for staring a package, rather mutate the metadata and acts as, the difference\n * is the users property which is part of the payload and the body only includes\n *\n * {\n\t\t \"_id\": pkgName,\n\t \t\"_rev\": \"3-b0cdaefc9bdb77c8\",\n\t\t \"users\": {\n\t\t [username]: boolean value (true, false)\n\t\t }\n\t }\n *\n * 4. Change owners of a package\n *\n * Similar to staring a package, changing owners (maintainers) of a package uses the publish\n * endpoint.\n *\n * The body includes a list of the new owners with the following format\n *\n * {\n\t\t \"_id\": pkgName,\n\t \t\"_rev\": \"4-b0cdaefc9bdb77c8\",\n\t\t \"maintainers\": [\n { \"name\": \"first owner\", \"email\": \"me@verdaccio.org\" },\n { \"name\": \"second owner\", \"email\": \"you@verdaccio.org\" },\n ...\n\t\t ]\n\t }\n *\n */\nexport default function publish(\n router: Router,\n auth: Auth,\n storage: Storage,\n logger: Logger\n): void {\n const can = allow(auth, {\n beforeAll: (a, b) => logger.trace(a, b),\n afterAll: (a, b) => logger.trace(a, b),\n });\n router.put(\n '/:package',\n can('publish'),\n media(mime.getType('json')),\n expectJson,\n publishPackage(storage, logger, 'publish one version')\n );\n\n router.put(\n '/:package/-rev/:revision',\n can('unpublish'),\n media(mime.getType('json')),\n expectJson,\n publishPackage(storage, logger, 'publish with revision')\n );\n\n /**\n * Un-publishing an entire package.\n *\n * This scenario happens when any of these scenarios happens:\n * - the first call detect there is only one version remaining\n * - no version is specified in the unpublish call\n * - all versions are removed npm unpublish package@*\n * - there is no versions on the metadata\n \n * then the client decides to DELETE the resource\n * Example:\n * Get fresh manifest (write=true is a flag to get the latest revision)\n * npm http fetch GET 304 http://localhost:4873/package-name?write=true 1076ms (from cache)\n * Send request to delete the package, this includes the revision number that must match\n * and the package name, it will delete the entire package and all tarballs (or tarball depends the scenario)\n * npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms\n */\n router.delete(\n '/:package/-rev/:revision',\n can('unpublish'),\n async function (req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {\n const packageName = req.params.package;\n const rev = req.params.revision;\n const username = req?.remote_user?.name;\n\n logger.debug({ packageName }, `unpublishing @{packageName}`);\n try {\n await storage.removePackage(packageName, rev, username);\n debug('package %s unpublished', packageName);\n res.status(HTTP_STATUS.CREATED);\n return next({ ok: API_MESSAGE.PKG_REMOVED });\n } catch (err) {\n return next(err);\n }\n }\n );\n\n /*\n Remove a tarball, this happens when npm unpublish a package unique version.\n npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms\n */\n router.delete(\n '/:package/-/:filename/-rev/:revision',\n can('unpublish'),\n can('publish'),\n async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n const packageName = req.params.package;\n const { filename, revision } = req.params;\n const username = req?.remote_user?.name;\n\n logger.debug(\n { packageName, filename, revision },\n `removing a tarball for @{packageName}-@{tarballName}-@{revision}`\n );\n try {\n await storage.removeTarball(packageName, filename, revision, username);\n res.status(HTTP_STATUS.CREATED);\n\n logger.debug(\n { packageName, filename, revision },\n `success remove tarball for @{packageName}-@{tarballName}-@{revision}`\n );\n return next({ ok: API_MESSAGE.TARBALL_REMOVED });\n } catch (err) {\n return next(err);\n }\n }\n );\n}\n\nexport function publishPackage(storage: Storage, logger: Logger, origin: string): any {\n return async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n debug(origin);\n const ac = new AbortController();\n const packageName = req.params.package;\n const { revision } = req.params;\n debug('publishing package %s', packageName);\n debug('revision %s', revision);\n if (debug.enabled) {\n debug('body %o', req.body);\n }\n const metadata = req.body;\n const username = req?.remote_user?.name;\n\n debug('publishing package %o for user %o', packageName, username);\n logger.debug(\n { packageName, username },\n 'publishing package @{packageName} for user @{username}'\n );\n\n try {\n const message = await storage.updateManifest(metadata, {\n name: packageName,\n revision,\n signal: ac.signal,\n requestOptions: {\n host: req.hostname,\n protocol: req.protocol,\n headers: req.headers as { [key: string]: string },\n username,\n },\n uplinksLook: false,\n });\n debug('package %s published', packageName);\n\n res.status(HTTP_STATUS.CREATED);\n\n return next({\n success: true,\n ok: message,\n });\n } catch (err: any) {\n // TODO: review if we need the abort controller here\n next(err);\n }\n };\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,KAAA,GAAAF,sBAAA,CAAAC,OAAA;AAGA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,WAAA,GAAAH,OAAA;AAAiE,SAAAD,uBAAAK,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAMjE;;AAEA,MAAMG,KAAK,GAAG,IAAAC,cAAU,EAAC,uBAAuB,CAAC;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,SAASC,OAAOA,CAC7BC,MAAc,EACdC,IAAU,EACVC,OAAgB,EAChBC,MAAc,EACR;EACN,MAAMC,GAAG,GAAG,IAAAC,iBAAK,EAACJ,IAAI,EAAE;IACtBK,SAAS,EAAEA,CAACC,CAAC,EAAEC,CAAC,KAAKL,MAAM,CAACM,KAAK,CAACF,CAAC,EAAEC,CAAC,CAAC;IACvCE,QAAQ,EAAEA,CAACH,CAAC,EAAEC,CAAC,KAAKL,MAAM,CAACM,KAAK,CAACF,CAAC,EAAEC,CAAC;EACvC,CAAC,CAAC;EACFR,MAAM,CAACW,GAAG,CACR,WAAW,EACXP,GAAG,CAAC,SAAS,CAAC,EACd,IAAAQ,iBAAK,EAACC,aAAI,CAACC,OAAO,CAAC,MAAM,CAAC,CAAC,EAC3BC,sBAAU,E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","ignoreList":[]}
package/build/user.js CHANGED
@@ -15,7 +15,7 @@ const debug = (0, _debug.default)('verdaccio:api:user');
15
15
  function _default(route, auth, config, logger) {
16
16
  route.get('/-/user/:org_couchdb_user', (0, _middleware.rateLimit)(config?.userRateLimit), function (req, res, next) {
17
17
  debug('verifying user');
18
- if (typeof req.remote_user.name !== 'string' || req.remote_user.name === '') {
18
+ if (!req.remote_user || typeof req.remote_user.name !== 'string' || req.remote_user.name === '') {
19
19
  debug('user not logged in');
20
20
  res.status(_core.HTTP_STATUS.OK);
21
21
  return next({
package/build/user.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"user.js","names":["_debug","_interopRequireDefault","require","_auth","_config","_core","_middleware","_utils","e","__esModule","default","debug","buildDebug","_default","route","auth","config","logger","get","rateLimit","userRateLimit","req","res","next","remote_user","name","status","HTTP_STATUS","OK","ok","username","params","org_couchdb_user","split","message","getAuthenticatedMessage","email","put","password","body","remoteName","validatioUtils","validateUserName","errorUtils","getBadRequest","API_ERROR","USERNAME_MISMATCH","authenticate","callbackAuthenticate","err","user","trace","getCode","UNAUTHORIZED","BAD_USERNAME_PASSWORD","restoredRemoteUser","createRemoteUser","groups","token","getApiToken","getUnauthorized","CREATED","set","HEADERS","CACHE_CONTROL","validatePassword","serverSettings","passwordValidationRegex","BAD_REQUEST","PASSWORD_SHORT","add_user","INTERNAL_ERROR","getConflict","undefined","mask","delete","API_MESSAGE","LOGGED_OUT"],"sources":["../src/user.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Response, Router } from 'express';\n\nimport { getApiToken } from '@verdaccio/auth';\nimport { Auth } from '@verdaccio/auth';\nimport { createRemoteUser } from '@verdaccio/config';\nimport {\n API_ERROR,\n API_MESSAGE,\n HEADERS,\n HTTP_STATUS,\n errorUtils,\n validatioUtils,\n} from '@verdaccio/core';\nimport { rateLimit } from '@verdaccio/middleware';\nimport { Logger } from '@verdaccio/types';\nimport { Config, RemoteUser } from '@verdaccio/types';\nimport { getAuthenticatedMessage, mask } from '@verdaccio/utils';\n\nimport { $NextFunctionVer, $RequestExtend } from '../types/custom';\n\nconst debug = buildDebug('verdaccio:api:user');\n\nexport default function (route: Router, auth: Auth, config: Config, logger: Logger): void {\n route.get(\n '/-/user/:org_couchdb_user',\n rateLimit(config?.userRateLimit),\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n debug('verifying user');\n\n if (typeof req.remote_user.name !== 'string' || req.remote_user.name === '') {\n debug('user not logged in');\n res.status(HTTP_STATUS.OK);\n return next({ ok: false });\n }\n\n const username = req.params.org_couchdb_user.split(':')[1];\n const message = getAuthenticatedMessage(req.remote_user.name);\n debug('user authenticated message %o', message);\n res.status(HTTP_STATUS.OK);\n next({\n // 'npm owner' requires user info\n // TODO: we don't have the email\n name: username,\n email: '',\n ok: message,\n });\n }\n );\n\n /**\n * \n * body example\n * req.body = {\n _id: \"org.couchdb.user:jjjj\",\n name: \"jjjj\",\n password: \"jjjj\",\n type: \"user\",\n roles: [],\n date: \"2022-07-08T15:51:04.002Z\",\n }\n * \n * @export\n * @param {Router} route\n * @param {Auth} auth\n * @param {Config} config\n */\n route.put(\n '/-/user/:org_couchdb_user/:_rev?/:revision?',\n rateLimit(config?.userRateLimit),\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n const { name, password } = req.body;\n debug('login or adduser');\n const remoteName = req?.remote_user?.name;\n\n if (!validatioUtils.validateUserName(req.params.org_couchdb_user, name)) {\n return next(errorUtils.getBadRequest(API_ERROR.USERNAME_MISMATCH));\n }\n\n if (typeof remoteName !== 'undefined' && typeof name === 'string' && remoteName === name) {\n debug('login: no remote user detected');\n auth.authenticate(\n name,\n password,\n async function callbackAuthenticate(err, user): Promise<void> {\n if (err) {\n logger.trace(\n { name, err },\n 'authenticating for user @{username} failed. Error: @{err.message}'\n );\n return next(\n errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.BAD_USERNAME_PASSWORD)\n );\n }\n\n const restoredRemoteUser: RemoteUser = createRemoteUser(name, user?.groups || []);\n const token = await getApiToken(auth, config, restoredRemoteUser, password);\n debug('login: new token');\n if (!token) {\n return next(errorUtils.getUnauthorized());\n }\n\n res.status(HTTP_STATUS.CREATED);\n res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');\n\n const message = getAuthenticatedMessage(req.remote_user.name);\n debug('login: created user message %o', message);\n\n return next({\n ok: message,\n token,\n });\n }\n );\n } else {\n debug('adduser: %o', name);\n if (\n validatioUtils.validatePassword(\n password,\n config?.serverSettings?.passwordValidationRegex\n ) === false\n ) {\n debug('adduser: invalid password');\n // eslint-disable-next-line new-cap\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT));\n }\n\n auth.add_user(name, password, async function (err, user): Promise<void> {\n if (err) {\n if (err.status >= HTTP_STATUS.BAD_REQUEST && err.status < HTTP_STATUS.INTERNAL_ERROR) {\n debug('adduser: error on create user');\n // With npm registering is the same as logging in,\n // and npm accepts only an 409 error.\n // So, changing status code here.\n return next(\n errorUtils.getCode(err.status, err.message) || errorUtils.getConflict(err.message)\n );\n }\n return next(err);\n }\n\n const token =\n name && password\n ? await getApiToken(auth, config, user as RemoteUser, password)\n : undefined;\n if (token) {\n debug('adduser: new token %o', mask(token as string, 4));\n }\n if (!token) {\n return next(errorUtils.getUnauthorized());\n }\n\n req.remote_user = user;\n res.status(HTTP_STATUS.CREATED);\n res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');\n debug('adduser: user has been created');\n return next({\n ok: `user '${req.body.name}' created`,\n token,\n });\n });\n }\n }\n );\n\n route.delete(\n '/-/user/token/*',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n res.status(HTTP_STATUS.OK);\n next({\n ok: API_MESSAGE.LOGGED_OUT,\n });\n }\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"user.js","names":["_debug","_interopRequireDefault","require","_auth","_config","_core","_middleware","_utils","e","__esModule","default","debug","buildDebug","_default","route","auth","config","logger","get","rateLimit","userRateLimit","req","res","next","remote_user","name","status","HTTP_STATUS","OK","ok","username","params","org_couchdb_user","split","message","getAuthenticatedMessage","email","put","password","body","remoteName","validatioUtils","validateUserName","errorUtils","getBadRequest","API_ERROR","USERNAME_MISMATCH","authenticate","callbackAuthenticate","err","user","trace","getCode","UNAUTHORIZED","BAD_USERNAME_PASSWORD","restoredRemoteUser","createRemoteUser","groups","token","getApiToken","getUnauthorized","CREATED","set","HEADERS","CACHE_CONTROL","validatePassword","serverSettings","passwordValidationRegex","BAD_REQUEST","PASSWORD_SHORT","add_user","INTERNAL_ERROR","getConflict","undefined","mask","delete","API_MESSAGE","LOGGED_OUT"],"sources":["../src/user.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Response, Router } from 'express';\n\nimport { getApiToken } from '@verdaccio/auth';\nimport { Auth } from '@verdaccio/auth';\nimport { createRemoteUser } from '@verdaccio/config';\nimport {\n API_ERROR,\n API_MESSAGE,\n HEADERS,\n HTTP_STATUS,\n errorUtils,\n validatioUtils,\n} from '@verdaccio/core';\nimport { rateLimit } from '@verdaccio/middleware';\nimport { Logger } from '@verdaccio/types';\nimport { Config, RemoteUser } from '@verdaccio/types';\nimport { getAuthenticatedMessage, mask } from '@verdaccio/utils';\n\nimport { $NextFunctionVer, $RequestExtend } from '../types/custom';\n\nconst debug = buildDebug('verdaccio:api:user');\n\nexport default function (route: Router, auth: Auth, config: Config, logger: Logger): void {\n route.get(\n '/-/user/:org_couchdb_user',\n rateLimit(config?.userRateLimit),\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n debug('verifying user');\n\n if (\n !req.remote_user ||\n typeof req.remote_user.name !== 'string' ||\n req.remote_user.name === ''\n ) {\n debug('user not logged in');\n res.status(HTTP_STATUS.OK);\n return next({ ok: false });\n }\n\n const username = req.params.org_couchdb_user.split(':')[1];\n const message = getAuthenticatedMessage(req.remote_user.name);\n debug('user authenticated message %o', message);\n res.status(HTTP_STATUS.OK);\n next({\n // 'npm owner' requires user info\n // TODO: we don't have the email\n name: username,\n email: '',\n ok: message,\n });\n }\n );\n\n /**\n * \n * body example\n * req.body = {\n _id: \"org.couchdb.user:jjjj\",\n name: \"jjjj\",\n password: \"jjjj\",\n type: \"user\",\n roles: [],\n date: \"2022-07-08T15:51:04.002Z\",\n }\n * \n * @export\n * @param {Router} route\n * @param {Auth} auth\n * @param {Config} config\n */\n route.put(\n '/-/user/:org_couchdb_user/:_rev?/:revision?',\n rateLimit(config?.userRateLimit),\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n const { name, password } = req.body;\n debug('login or adduser');\n const remoteName = req?.remote_user?.name;\n\n if (!validatioUtils.validateUserName(req.params.org_couchdb_user, name)) {\n return next(errorUtils.getBadRequest(API_ERROR.USERNAME_MISMATCH));\n }\n\n if (typeof remoteName !== 'undefined' && typeof name === 'string' && remoteName === name) {\n debug('login: no remote user detected');\n auth.authenticate(\n name,\n password,\n async function callbackAuthenticate(err, user): Promise<void> {\n if (err) {\n logger.trace(\n { name, err },\n 'authenticating for user @{username} failed. Error: @{err.message}'\n );\n return next(\n errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.BAD_USERNAME_PASSWORD)\n );\n }\n\n const restoredRemoteUser: RemoteUser = createRemoteUser(name, user?.groups || []);\n const token = await getApiToken(auth, config, restoredRemoteUser, password);\n debug('login: new token');\n if (!token) {\n return next(errorUtils.getUnauthorized());\n }\n\n res.status(HTTP_STATUS.CREATED);\n res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');\n\n const message = getAuthenticatedMessage(req.remote_user.name);\n debug('login: created user message %o', message);\n\n return next({\n ok: message,\n token,\n });\n }\n );\n } else {\n debug('adduser: %o', name);\n if (\n validatioUtils.validatePassword(\n password,\n config?.serverSettings?.passwordValidationRegex\n ) === false\n ) {\n debug('adduser: invalid password');\n // eslint-disable-next-line new-cap\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT));\n }\n\n auth.add_user(name, password, async function (err, user): Promise<void> {\n if (err) {\n if (err.status >= HTTP_STATUS.BAD_REQUEST && err.status < HTTP_STATUS.INTERNAL_ERROR) {\n debug('adduser: error on create user');\n // With npm registering is the same as logging in,\n // and npm accepts only an 409 error.\n // So, changing status code here.\n return next(\n errorUtils.getCode(err.status, err.message) || errorUtils.getConflict(err.message)\n );\n }\n return next(err);\n }\n\n const token =\n name && password\n ? await getApiToken(auth, config, user as RemoteUser, password)\n : undefined;\n if (token) {\n debug('adduser: new token %o', mask(token as string, 4));\n }\n if (!token) {\n return next(errorUtils.getUnauthorized());\n }\n\n req.remote_user = user;\n res.status(HTTP_STATUS.CREATED);\n res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');\n debug('adduser: user has been created');\n return next({\n ok: `user '${req.body.name}' created`,\n token,\n });\n });\n }\n }\n );\n\n route.delete(\n '/-/user/token/*',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n res.status(HTTP_STATUS.OK);\n next({\n ok: API_MESSAGE.LOGGED_OUT,\n });\n }\n );\n}\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/api",
3
- "version": "8.1.0-next-8.4",
3
+ "version": "8.1.0-next-8.5",
4
4
  "description": "loaders logic",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -29,25 +29,25 @@
29
29
  },
30
30
  "license": "MIT",
31
31
  "dependencies": {
32
- "@verdaccio/auth": "8.0.0-next-8.4",
33
- "@verdaccio/config": "8.0.0-next-8.4",
34
- "@verdaccio/core": "8.0.0-next-8.4",
35
- "@verdaccio/logger": "8.0.0-next-8.4",
36
- "@verdaccio/middleware": "8.0.0-next-8.4",
37
- "@verdaccio/store": "8.0.0-next-8.4",
38
- "@verdaccio/utils": "8.1.0-next-8.4",
39
- "abortcontroller-polyfill": "1.7.5",
32
+ "@verdaccio/auth": "8.0.0-next-8.5",
33
+ "@verdaccio/config": "8.0.0-next-8.5",
34
+ "@verdaccio/core": "8.0.0-next-8.5",
35
+ "@verdaccio/logger": "8.0.0-next-8.5",
36
+ "@verdaccio/middleware": "8.0.0-next-8.5",
37
+ "@verdaccio/store": "8.0.0-next-8.5",
38
+ "@verdaccio/utils": "8.1.0-next-8.5",
39
+ "abortcontroller-polyfill": "1.7.6",
40
40
  "body-parser": "1.20.3",
41
41
  "cookies": "0.9.1",
42
42
  "debug": "4.3.7",
43
- "express": "4.21.1",
43
+ "express": "4.21.2",
44
44
  "lodash": "4.17.21",
45
45
  "mime": "2.6.0",
46
46
  "semver": "7.6.3"
47
47
  },
48
48
  "devDependencies": {
49
- "@verdaccio/test-helper": "4.0.0-next-8.1",
50
- "@verdaccio/types": "13.0.0-next-8.1",
49
+ "@verdaccio/test-helper": "4.0.0-next-8.2",
50
+ "@verdaccio/types": "13.0.0-next-8.2",
51
51
  "mockdate": "3.0.5",
52
52
  "nock": "13.5.1",
53
53
  "supertest": "7.0.0"
package/src/package.ts CHANGED
@@ -24,13 +24,24 @@ export default function (route: Router, auth: Auth, storage: Storage, logger: Lo
24
24
  _res: $ResponseExtend,
25
25
  next: $NextFunctionVer
26
26
  ): Promise<void> {
27
- debug('init package by version');
27
+ debug('get package by version');
28
28
  const name = req.params.package;
29
29
  let version = req.params.version;
30
30
  const write = req.query.write === 'true';
31
31
  const username = req?.remote_user?.name;
32
32
  const abbreviated =
33
33
  stringUtils.getByQualityPriorityValue(req.get('Accept')) === Storage.ABBREVIATED_HEADER;
34
+ if (debug.enabled) {
35
+ debug('is write %o', write);
36
+ debug('is abbreviated %o', abbreviated);
37
+ debug('package %o', name);
38
+ debug('version %o', version);
39
+ debug('username %o', username);
40
+ debug('remote address %o', req.socket.remoteAddress);
41
+ debug('host %o', req.host);
42
+ debug('protocol %o', req.protocol);
43
+ debug('url %o', req.url);
44
+ }
34
45
  const requestOptions = {
35
46
  protocol: req.protocol,
36
47
  headers: req.headers as any,
@@ -50,8 +61,10 @@ export default function (route: Router, auth: Auth, storage: Storage, logger: Lo
50
61
  requestOptions,
51
62
  });
52
63
  if (abbreviated) {
64
+ debug('abbreviated response');
53
65
  _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET);
54
66
  } else {
67
+ debug('full response');
55
68
  _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
56
69
  }
57
70
 
@@ -69,6 +82,7 @@ export default function (route: Router, auth: Auth, storage: Storage, logger: Lo
69
82
  const { package: pkgName, filename } = req.params;
70
83
  const abort = new AbortController();
71
84
  try {
85
+ debug('downloading tarball %o', filename);
72
86
  const stream = (await storage.getTarball(pkgName, filename, {
73
87
  signal: abort.signal,
74
88
  // TODO: review why this param
@@ -76,10 +90,12 @@ export default function (route: Router, auth: Auth, storage: Storage, logger: Lo
76
90
  })) as any;
77
91
 
78
92
  stream.on('content-length', (size) => {
93
+ debug('tarball size %o', size);
79
94
  res.header(HEADER_TYPE.CONTENT_LENGTH, size);
80
95
  });
81
96
 
82
97
  stream.once('error', (err) => {
98
+ debug('error on download tarball %o', err);
83
99
  res.locals.report_error(err);
84
100
  next(err);
85
101
  });
@@ -92,7 +108,6 @@ export default function (route: Router, auth: Auth, storage: Storage, logger: Lo
92
108
  res.header(HEADERS.CONTENT_TYPE, HEADERS.OCTET_STREAM);
93
109
  stream.pipe(res);
94
110
  } catch (err: any) {
95
- // console.log('catch API error request', err);
96
111
  res.locals.report_error(err);
97
112
  next(err);
98
113
  }
package/src/publish.ts CHANGED
@@ -73,7 +73,7 @@ const debug = buildDebug('verdaccio:api:publish');
73
73
  * npm http fetch GET 200 http://localhost:4873/custom-name?write=true 1601ms
74
74
  * Remove the tarball
75
75
  * npm http fetch DELETE 201 http://localhost:4873/custom-name/-/test1-1.0.3.tgz/-rev/16-e11c8db282b2d992 19ms
76
- *
76
+ *
77
77
  * 3. Star a package
78
78
  *
79
79
  * Permissions: staring a package depends of the publish and unpublish permissions, there is no
@@ -94,7 +94,7 @@ const debug = buildDebug('verdaccio:api:publish');
94
94
  * 4. Change owners of a package
95
95
  *
96
96
  * Similar to staring a package, changing owners (maintainers) of a package uses the publish
97
- * endpoint.
97
+ * endpoint.
98
98
  *
99
99
  * The body includes a list of the new owners with the following format
100
100
  *
@@ -124,7 +124,7 @@ export default function publish(
124
124
  can('publish'),
125
125
  media(mime.getType('json')),
126
126
  expectJson,
127
- publishPackage(storage, logger)
127
+ publishPackage(storage, logger, 'publish one version')
128
128
  );
129
129
 
130
130
  router.put(
@@ -132,15 +132,24 @@ export default function publish(
132
132
  can('unpublish'),
133
133
  media(mime.getType('json')),
134
134
  expectJson,
135
- publishPackage(storage, logger)
135
+ publishPackage(storage, logger, 'publish with revision')
136
136
  );
137
137
 
138
138
  /**
139
139
  * Un-publishing an entire package.
140
140
  *
141
- * This scenario happens when the first call detect there is only one version remaining
142
- * in the metadata, then the client decides to DELETE the resource
141
+ * This scenario happens when any of these scenarios happens:
142
+ * - the first call detect there is only one version remaining
143
+ * - no version is specified in the unpublish call
144
+ * - all versions are removed npm unpublish package@*
145
+ * - there is no versions on the metadata
146
+
147
+ * then the client decides to DELETE the resource
148
+ * Example:
149
+ * Get fresh manifest (write=true is a flag to get the latest revision)
143
150
  * npm http fetch GET 304 http://localhost:4873/package-name?write=true 1076ms (from cache)
151
+ * Send request to delete the package, this includes the revision number that must match
152
+ * and the package name, it will delete the entire package and all tarballs (or tarball depends the scenario)
144
153
  * npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms
145
154
  */
146
155
  router.delete(
@@ -200,15 +209,21 @@ export default function publish(
200
209
  );
201
210
  }
202
211
 
203
- export function publishPackage(storage: Storage, logger: Logger): any {
212
+ export function publishPackage(storage: Storage, logger: Logger, origin: string): any {
204
213
  return async function (
205
214
  req: $RequestExtend,
206
215
  res: $ResponseExtend,
207
216
  next: $NextFunctionVer
208
217
  ): Promise<void> {
218
+ debug(origin);
209
219
  const ac = new AbortController();
210
220
  const packageName = req.params.package;
211
221
  const { revision } = req.params;
222
+ debug('publishing package %s', packageName);
223
+ debug('revision %s', revision);
224
+ if (debug.enabled) {
225
+ debug('body %o', req.body);
226
+ }
212
227
  const metadata = req.body;
213
228
  const username = req?.remote_user?.name;
214
229
 
@@ -231,6 +246,7 @@ export function publishPackage(storage: Storage, logger: Logger): any {
231
246
  },
232
247
  uplinksLook: false,
233
248
  });
249
+ debug('package %s published', packageName);
234
250
 
235
251
  res.status(HTTP_STATUS.CREATED);
236
252
 
package/src/user.ts CHANGED
@@ -28,7 +28,11 @@ export default function (route: Router, auth: Auth, config: Config, logger: Logg
28
28
  function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
29
29
  debug('verifying user');
30
30
 
31
- if (typeof req.remote_user.name !== 'string' || req.remote_user.name === '') {
31
+ if (
32
+ !req.remote_user ||
33
+ typeof req.remote_user.name !== 'string' ||
34
+ req.remote_user.name === ''
35
+ ) {
32
36
  debug('user not logged in');
33
37
  res.status(HTTP_STATUS.OK);
34
38
  return next({ ok: false });
@@ -31,12 +31,13 @@ describe('package', () => {
31
31
  ['@scope/foo2', 'foo2-1.0.0.tgz'],
32
32
  ])('should fails if tarball does not exist', async (pkg, fileName) => {
33
33
  await publishVersion(app, pkg, '1.0.1');
34
- return await supertest(app)
34
+ await supertest(app)
35
35
  .get(`/${pkg}/-/${fileName}`)
36
36
  .set(HEADERS.ACCEPT, HEADERS.JSON)
37
37
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.OCTET_STREAM)
38
38
  .expect(HTTP_STATUS.NOT_FOUND);
39
39
  });
40
+
40
41
  test.todo('check content length file header');
41
42
  test.todo('fails on file was aborted');
42
43
  });
@@ -97,8 +98,8 @@ describe('package', () => {
97
98
  expect(response.body.time).toBeDefined();
98
99
  expect(response.body.modified).toBeDefined();
99
100
  expect(response.body[DIST_TAGS]).toEqual({ latest: '1.0.0' });
100
- expect(response.body.readme).not.toBeDefined();
101
- expect(response.body._rev).not.toBeDefined();
101
+ expect(response.body.readme).toBeDefined();
102
+ expect(response.body._rev).toBeDefined();
102
103
  expect(response.body.users).not.toBeDefined();
103
104
  }
104
105
  );
@@ -57,7 +57,7 @@ describe('publish', () => {
57
57
  async (pkgName) => {
58
58
  const app = await initializeServer('publish.yaml');
59
59
  await publishVersion(app, pkgName, '1.0.0');
60
- return new Promise((resolve) => {
60
+ new Promise((resolve) => {
61
61
  publishVersion(app, pkgName, '1.0.0')
62
62
  .expect(HTTP_STATUS.CONFLICT)
63
63
  .then((response) => {
@@ -73,7 +73,7 @@ describe('publish', () => {
73
73
  describe('no proxies setup', () => {
74
74
  test.each([['foo', '@scope/foo']])('should publish a package', async (pkgName) => {
75
75
  const app = await initializeServer('publish.yaml');
76
- return new Promise((resolve) => {
76
+ new Promise((resolve) => {
77
77
  publishVersion(app, pkgName, '1.0.0')
78
78
  .expect(HTTP_STATUS.CREATED)
79
79
  .then((response) => {
@@ -86,7 +86,7 @@ describe('publish', () => {
86
86
  test.each([['foo', '@scope/foo']])('should publish a new package', async (pkgName) => {
87
87
  const pkgMetadata = generatePackageMetadata(pkgName, '1.0.0');
88
88
  const app = await initializeServer('publish.yaml');
89
- return new Promise((resolve) => {
89
+ new Promise((resolve) => {
90
90
  supertest(app)
91
91
  .put(`/${encodeURIComponent(pkgName)}`)
92
92
  .set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
@@ -65,7 +65,7 @@ describe('star', () => {
65
65
  const app = await initializeServer('star.yaml');
66
66
  const token = await getNewToken(app, { name: userLogged, password: 'secretPass' });
67
67
  await publishVersion(app, pkgName, '1.0.0', undefined, token).expect(HTTP_STATUS.CREATED);
68
- return supertest(app)
68
+ await supertest(app)
69
69
  .get(`/-/_view/starredByUser?key_xxxxx=other`)
70
70
  .set('Accept', HEADERS.JSON)
71
71
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)