@verdaccio/api 6.0.0-6-next.29 → 6.0.0-6-next.31

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,95 @@
1
1
  # @verdaccio/api
2
2
 
3
+ ## 6.0.0-6-next.31
4
+
5
+ ### Major Changes
6
+
7
+ - 9fc2e796: feat(plugins): improve plugin loader
8
+
9
+ ### Changes
10
+
11
+ - Add scope plugin support to 6.x https://github.com/verdaccio/verdaccio/pull/3227
12
+ - Avoid config collisions https://github.com/verdaccio/verdaccio/issues/928
13
+ - https://github.com/verdaccio/verdaccio/issues/1394
14
+ - `config.plugins` plugin path validations
15
+ - Updated algorithm for plugin loader.
16
+ - improved documentation (included dev)
17
+
18
+ ## Features
19
+
20
+ - Add scope plugin support to 6.x https://github.com/verdaccio/verdaccio/pull/3227
21
+ - Custom prefix:
22
+
23
+ ```
24
+ // config.yaml
25
+ server:
26
+ pluginPrefix: mycompany
27
+ middleware:
28
+ audit:
29
+ foo: 1
30
+ ```
31
+
32
+ This configuration will look up for `mycompany-audit` instead `Verdaccio-audit`.
33
+
34
+ ## Breaking Changes
35
+
36
+ ### sinopia plugins
37
+
38
+ - `sinopia` fallback support is removed, but can be restored using `pluginPrefix`
39
+
40
+ ### plugin filter
41
+
42
+ - method rename `filter_metadata`->`filterMetadata`
43
+
44
+ ### Plugin constructor does not merge configs anymore https://github.com/verdaccio/verdaccio/issues/928
45
+
46
+ The plugin receives as first argument `config`, which represents the config of the plugin. Example:
47
+
48
+ ```
49
+ // config.yaml
50
+ auth:
51
+ plugin:
52
+ foo: 1
53
+ bar: 2
54
+
55
+ export class Plugin<T> {
56
+ public constructor(config: T, options: PluginOptions) {
57
+ console.log(config);
58
+ // {foo:1, bar: 2}
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### Minor Changes
64
+
65
+ - 62c24b63: feat: add passwordValidationRegex property
66
+
67
+ ### Patch Changes
68
+
69
+ - 43f32687: fix: abbreviated headers handle quality values
70
+ - Updated dependencies [43f32687]
71
+ - Updated dependencies [9fc2e796]
72
+ - Updated dependencies [62c24b63]
73
+ - @verdaccio/core@6.0.0-6-next.48
74
+ - @verdaccio/store@6.0.0-6-next.28
75
+ - @verdaccio/auth@6.0.0-6-next.27
76
+ - @verdaccio/config@6.0.0-6-next.48
77
+ - @verdaccio/utils@6.0.0-6-next.16
78
+ - @verdaccio/logger@6.0.0-6-next.16
79
+ - @verdaccio/middleware@6.0.0-6-next.27
80
+
81
+ ## 6.0.0-6-next.30
82
+
83
+ ### Patch Changes
84
+
85
+ - @verdaccio/core@6.0.0-6-next.47
86
+ - @verdaccio/config@6.0.0-6-next.47
87
+ - @verdaccio/auth@6.0.0-6-next.26
88
+ - @verdaccio/logger@6.0.0-6-next.15
89
+ - @verdaccio/middleware@6.0.0-6-next.26
90
+ - @verdaccio/store@6.0.0-6-next.27
91
+ - @verdaccio/utils@6.0.0-6-next.15
92
+
3
93
  ## 6.0.0-6-next.29
4
94
 
5
95
  ### Patch Changes
package/build/index.js CHANGED
@@ -66,7 +66,7 @@ function _default(config, auth, storage) {
66
66
 
67
67
  (0, _whoami.default)(app);
68
68
  (0, _package.default)(app, auth, storage);
69
- (0, _profile.default)(app, auth); // @deprecated endpoint, 404 by default
69
+ (0, _profile.default)(app, auth, config); // @deprecated endpoint, 404 by default
70
70
 
71
71
  (0, _search.default)(app);
72
72
  (0, _user.default)(app, auth, config);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["config","auth","storage","app","express","Router","param","validatePackage","validateName","match","use","apiJWTmiddleware","bodyParser","json","strict","limit","max_body_size","antiLoop","encodeScopePackage","whoami","pkg","profile","search","user","distTags","publish","ping","stars","v1Search","token"],"sources":["../src/index.ts"],"sourcesContent":["import bodyParser from 'body-parser';\nimport express, { Router } from 'express';\n\nimport { IAuth } from '@verdaccio/auth';\nimport {\n antiLoop,\n encodeScopePackage,\n match,\n validateName,\n validatePackage,\n} from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\nimport { Config } from '@verdaccio/types';\n\nimport distTags from './dist-tags';\nimport pkg from './package';\nimport ping from './ping';\nimport publish from './publish';\nimport search from './search';\nimport stars from './stars';\nimport user from './user';\nimport profile from './v1/profile';\nimport v1Search from './v1/search';\nimport token from './v1/token';\nimport whoami from './whoami';\n\nexport default function (config: Config, auth: IAuth, storage: Storage): Router {\n /* eslint new-cap:off */\n const app = express.Router();\n /* eslint new-cap:off */\n\n // validate all of these params as a package name\n // this might be too harsh, so ask if it causes trouble\n app.param('package', validatePackage);\n app.param('filename', validateName);\n app.param('tag', validateName);\n app.param('version', validateName);\n app.param('revision', validateName);\n app.param('token', validateName);\n\n // these can't be safely put into express url for some reason\n // TODO: For some reason? what reason?\n app.param('_rev', match(/^-rev$/));\n app.param('org_couchdb_user', match(/^org\\.couchdb\\.user:/));\n app.param('anything', match(/.*/));\n app.use(auth.apiJWTmiddleware());\n app.use(bodyParser.json({ strict: false, limit: config.max_body_size || '10mb' }));\n // @ts-ignore\n app.use(antiLoop(config));\n // encode / in a scoped package name to be matched as a single parameter in routes\n app.use(encodeScopePackage);\n // for \"npm whoami\"\n whoami(app);\n pkg(app, auth, storage);\n profile(app, auth);\n // @deprecated endpoint, 404 by default\n search(app);\n user(app, auth, config);\n distTags(app, auth, storage);\n publish(app, auth, storage);\n ping(app);\n stars(app, storage);\n // @ts-ignore\n v1Search(app, auth, storage);\n token(app, auth, storage, config);\n return app;\n}\n"],"mappings":";;;;;;;AAAA;;AACA;;AAGA;;AAUA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEe,kBAAUA,MAAV,EAA0BC,IAA1B,EAAuCC,OAAvC,EAAiE;EAC9E;EACA,MAAMC,GAAG,GAAGC,gBAAA,CAAQC,MAAR,EAAZ;EACA;EAEA;EACA;;;EACAF,GAAG,CAACG,KAAJ,CAAU,SAAV,EAAqBC,2BAArB;EACAJ,GAAG,CAACG,KAAJ,CAAU,UAAV,EAAsBE,wBAAtB;EACAL,GAAG,CAACG,KAAJ,CAAU,KAAV,EAAiBE,wBAAjB;EACAL,GAAG,CAACG,KAAJ,CAAU,SAAV,EAAqBE,wBAArB;EACAL,GAAG,CAACG,KAAJ,CAAU,UAAV,EAAsBE,wBAAtB;EACAL,GAAG,CAACG,KAAJ,CAAU,OAAV,EAAmBE,wBAAnB,EAZ8E,CAc9E;EACA;;EACAL,GAAG,CAACG,KAAJ,CAAU,MAAV,EAAkB,IAAAG,iBAAA,EAAM,QAAN,CAAlB;EACAN,GAAG,CAACG,KAAJ,CAAU,kBAAV,EAA8B,IAAAG,iBAAA,EAAM,sBAAN,CAA9B;EACAN,GAAG,CAACG,KAAJ,CAAU,UAAV,EAAsB,IAAAG,iBAAA,EAAM,IAAN,CAAtB;EACAN,GAAG,CAACO,GAAJ,CAAQT,IAAI,CAACU,gBAAL,EAAR;EACAR,GAAG,CAACO,GAAJ,CAAQE,mBAAA,CAAWC,IAAX,CAAgB;IAAEC,MAAM,EAAE,KAAV;IAAiBC,KAAK,EAAEf,MAAM,CAACgB,aAAP,IAAwB;EAAhD,CAAhB,CAAR,EApB8E,CAqB9E;;EACAb,GAAG,CAACO,GAAJ,CAAQ,IAAAO,oBAAA,EAASjB,MAAT,CAAR,EAtB8E,CAuB9E;;EACAG,GAAG,CAACO,GAAJ,CAAQQ,8BAAR,EAxB8E,CAyB9E;;EACA,IAAAC,eAAA,EAAOhB,GAAP;EACA,IAAAiB,gBAAA,EAAIjB,GAAJ,EAASF,IAAT,EAAeC,OAAf;EACA,IAAAmB,gBAAA,EAAQlB,GAAR,EAAaF,IAAb,EA5B8E,CA6B9E;;EACA,IAAAqB,eAAA,EAAOnB,GAAP;EACA,IAAAoB,aAAA,EAAKpB,GAAL,EAAUF,IAAV,EAAgBD,MAAhB;EACA,IAAAwB,iBAAA,EAASrB,GAAT,EAAcF,IAAd,EAAoBC,OAApB;EACA,IAAAuB,gBAAA,EAAQtB,GAAR,EAAaF,IAAb,EAAmBC,OAAnB;EACA,IAAAwB,aAAA,EAAKvB,GAAL;EACA,IAAAwB,cAAA,EAAMxB,GAAN,EAAWD,OAAX,EAnC8E,CAoC9E;;EACA,IAAA0B,gBAAA,EAASzB,GAAT,EAAcF,IAAd,EAAoBC,OAApB;EACA,IAAA2B,cAAA,EAAM1B,GAAN,EAAWF,IAAX,EAAiBC,OAAjB,EAA0BF,MAA1B;EACA,OAAOG,GAAP;AACD"}
1
+ {"version":3,"file":"index.js","names":["config","auth","storage","app","express","Router","param","validatePackage","validateName","match","use","apiJWTmiddleware","bodyParser","json","strict","limit","max_body_size","antiLoop","encodeScopePackage","whoami","pkg","profile","search","user","distTags","publish","ping","stars","v1Search","token"],"sources":["../src/index.ts"],"sourcesContent":["import bodyParser from 'body-parser';\nimport express, { Router } from 'express';\n\nimport { IAuth } from '@verdaccio/auth';\nimport {\n antiLoop,\n encodeScopePackage,\n match,\n validateName,\n validatePackage,\n} from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\nimport { Config } from '@verdaccio/types';\n\nimport distTags from './dist-tags';\nimport pkg from './package';\nimport ping from './ping';\nimport publish from './publish';\nimport search from './search';\nimport stars from './stars';\nimport user from './user';\nimport profile from './v1/profile';\nimport v1Search from './v1/search';\nimport token from './v1/token';\nimport whoami from './whoami';\n\nexport default function (config: Config, auth: IAuth, storage: Storage): Router {\n /* eslint new-cap:off */\n const app = express.Router();\n /* eslint new-cap:off */\n\n // validate all of these params as a package name\n // this might be too harsh, so ask if it causes trouble\n app.param('package', validatePackage);\n app.param('filename', validateName);\n app.param('tag', validateName);\n app.param('version', validateName);\n app.param('revision', validateName);\n app.param('token', validateName);\n\n // these can't be safely put into express url for some reason\n // TODO: For some reason? what reason?\n app.param('_rev', match(/^-rev$/));\n app.param('org_couchdb_user', match(/^org\\.couchdb\\.user:/));\n app.param('anything', match(/.*/));\n app.use(auth.apiJWTmiddleware());\n app.use(bodyParser.json({ strict: false, limit: config.max_body_size || '10mb' }));\n // @ts-ignore\n app.use(antiLoop(config));\n // encode / in a scoped package name to be matched as a single parameter in routes\n app.use(encodeScopePackage);\n // for \"npm whoami\"\n whoami(app);\n pkg(app, auth, storage);\n profile(app, auth, config);\n // @deprecated endpoint, 404 by default\n search(app);\n user(app, auth, config);\n distTags(app, auth, storage);\n publish(app, auth, storage);\n ping(app);\n stars(app, storage);\n // @ts-ignore\n v1Search(app, auth, storage);\n token(app, auth, storage, config);\n return app;\n}\n"],"mappings":";;;;;;;AAAA;;AACA;;AAGA;;AAUA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEe,kBAAUA,MAAV,EAA0BC,IAA1B,EAAuCC,OAAvC,EAAiE;EAC9E;EACA,MAAMC,GAAG,GAAGC,gBAAA,CAAQC,MAAR,EAAZ;EACA;EAEA;EACA;;;EACAF,GAAG,CAACG,KAAJ,CAAU,SAAV,EAAqBC,2BAArB;EACAJ,GAAG,CAACG,KAAJ,CAAU,UAAV,EAAsBE,wBAAtB;EACAL,GAAG,CAACG,KAAJ,CAAU,KAAV,EAAiBE,wBAAjB;EACAL,GAAG,CAACG,KAAJ,CAAU,SAAV,EAAqBE,wBAArB;EACAL,GAAG,CAACG,KAAJ,CAAU,UAAV,EAAsBE,wBAAtB;EACAL,GAAG,CAACG,KAAJ,CAAU,OAAV,EAAmBE,wBAAnB,EAZ8E,CAc9E;EACA;;EACAL,GAAG,CAACG,KAAJ,CAAU,MAAV,EAAkB,IAAAG,iBAAA,EAAM,QAAN,CAAlB;EACAN,GAAG,CAACG,KAAJ,CAAU,kBAAV,EAA8B,IAAAG,iBAAA,EAAM,sBAAN,CAA9B;EACAN,GAAG,CAACG,KAAJ,CAAU,UAAV,EAAsB,IAAAG,iBAAA,EAAM,IAAN,CAAtB;EACAN,GAAG,CAACO,GAAJ,CAAQT,IAAI,CAACU,gBAAL,EAAR;EACAR,GAAG,CAACO,GAAJ,CAAQE,mBAAA,CAAWC,IAAX,CAAgB;IAAEC,MAAM,EAAE,KAAV;IAAiBC,KAAK,EAAEf,MAAM,CAACgB,aAAP,IAAwB;EAAhD,CAAhB,CAAR,EApB8E,CAqB9E;;EACAb,GAAG,CAACO,GAAJ,CAAQ,IAAAO,oBAAA,EAASjB,MAAT,CAAR,EAtB8E,CAuB9E;;EACAG,GAAG,CAACO,GAAJ,CAAQQ,8BAAR,EAxB8E,CAyB9E;;EACA,IAAAC,eAAA,EAAOhB,GAAP;EACA,IAAAiB,gBAAA,EAAIjB,GAAJ,EAASF,IAAT,EAAeC,OAAf;EACA,IAAAmB,gBAAA,EAAQlB,GAAR,EAAaF,IAAb,EAAmBD,MAAnB,EA5B8E,CA6B9E;;EACA,IAAAsB,eAAA,EAAOnB,GAAP;EACA,IAAAoB,aAAA,EAAKpB,GAAL,EAAUF,IAAV,EAAgBD,MAAhB;EACA,IAAAwB,iBAAA,EAASrB,GAAT,EAAcF,IAAd,EAAoBC,OAApB;EACA,IAAAuB,gBAAA,EAAQtB,GAAR,EAAaF,IAAb,EAAmBC,OAAnB;EACA,IAAAwB,aAAA,EAAKvB,GAAL;EACA,IAAAwB,cAAA,EAAMxB,GAAN,EAAWD,OAAX,EAnC8E,CAoC9E;;EACA,IAAA0B,gBAAA,EAASzB,GAAT,EAAcF,IAAd,EAAoBC,OAApB;EACA,IAAA2B,cAAA,EAAM1B,GAAN,EAAWF,IAAX,EAAiBC,OAAjB,EAA0BF,MAA1B;EACA,OAAOG,GAAP;AACD"}
package/build/package.js CHANGED
@@ -25,7 +25,7 @@ function _default(route, auth, storage) {
25
25
  let version = req.params.version;
26
26
  const write = req.query.write === 'true';
27
27
 
28
- const abbreviated = req.get('Accept') === _store.Storage.ABBREVIATED_HEADER;
28
+ const abbreviated = _core.stringUtils.getByQualityPriorityValue(req.get('Accept')) === _store.Storage.ABBREVIATED_HEADER;
29
29
 
30
30
  const requestOptions = {
31
31
  protocol: req.protocol,
@@ -44,6 +44,13 @@ function _default(route, auth, storage) {
44
44
  version,
45
45
  requestOptions
46
46
  });
47
+
48
+ if (abbreviated) {
49
+ _res.setHeader(_core.HEADER_TYPE.CONTENT_TYPE, _core.HEADERS.JSON_INSTALL_CHARSET);
50
+ } else {
51
+ _res.setHeader(_core.HEADER_TYPE.CONTENT_TYPE, _core.HEADERS.JSON);
52
+ }
53
+
47
54
  next(manifest);
48
55
  } catch (err) {
49
56
  next(err);
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":["debug","buildDebug","route","auth","storage","can","allow","get","req","_res","next","name","params","package","version","write","query","abbreviated","Storage","ABBREVIATED_HEADER","requestOptions","protocol","headers","host","remoteAddress","socket","byPassCache","manifest","getPackageByOptions","uplinksLook","err","res","pkg","filename","abort","AbortController","stream","getTarballNext","signal","on","size","header","HEADER_TYPE","CONTENT_LENGTH","once","locals","report_error","url","HEADERS","CONTENT_TYPE","OCTET_STREAM","pipe"],"sources":["../src/package.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\n\nimport { IAuth } from '@verdaccio/auth';\nimport { HEADERS, HEADER_TYPE } from '@verdaccio/core';\nimport { allow } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\nconst debug = buildDebug('verdaccio:api:package');\n\nexport default function (route: Router, auth: IAuth, storage: Storage): void {\n const can = allow(auth);\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 abbreviated = 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 };\n\n try {\n const manifest = await storage.getPackageByOptions({\n name,\n uplinksLook: true,\n abbreviated,\n version,\n requestOptions,\n });\n next(manifest);\n } catch (err) {\n next(err);\n }\n }\n );\n\n route.get(\n '/:pkg/-/:filename',\n can('access'),\n async function (req: $RequestExtend, res: $ResponseExtend, next): Promise<void> {\n const { pkg, filename } = req.params;\n const abort = new AbortController();\n try {\n const stream = (await storage.getTarballNext(pkg, 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":";;;;;;;AAAA;;AAIA;;AACA;;AACA;;;;AAIA,MAAMA,KAAK,GAAG,IAAAC,cAAA,EAAW,uBAAX,CAAd;;AAEe,kBAAUC,KAAV,EAAyBC,IAAzB,EAAsCC,OAAtC,EAA8D;EAC3E,MAAMC,GAAG,GAAG,IAAAC,iBAAA,EAAMH,IAAN,CAAZ;EAEAD,KAAK,CAACK,GAAN,CACE,qBADF,EAEEF,GAAG,CAAC,QAAD,CAFL,EAGE,gBACEG,GADF,EAEEC,IAFF,EAGEC,IAHF,EAIiB;IACfV,KAAK,CAAC,yBAAD,CAAL;IACA,MAAMW,IAAI,GAAGH,GAAG,CAACI,MAAJ,CAAWC,OAAxB;IACA,IAAIC,OAAO,GAAGN,GAAG,CAACI,MAAJ,CAAWE,OAAzB;IACA,MAAMC,KAAK,GAAGP,GAAG,CAACQ,KAAJ,CAAUD,KAAV,KAAoB,MAAlC;;IACA,MAAME,WAAW,GAAGT,GAAG,CAACD,GAAJ,CAAQ,QAAR,MAAsBW,cAAA,CAAQC,kBAAlD;;IACA,MAAMC,cAAc,GAAG;MACrBC,QAAQ,EAAEb,GAAG,CAACa,QADO;MAErBC,OAAO,EAAEd,GAAG,CAACc,OAFQ;MAGrB;MACAC,IAAI,EAAEf,GAAG,CAACe,IAJW;MAKrBC,aAAa,EAAEhB,GAAG,CAACiB,MAAJ,CAAWD,aALL;MAMrBE,WAAW,EAAEX;IANQ,CAAvB;;IASA,IAAI;MACF,MAAMY,QAAQ,GAAG,MAAMvB,OAAO,CAACwB,mBAAR,CAA4B;QACjDjB,IADiD;QAEjDkB,WAAW,EAAE,IAFoC;QAGjDZ,WAHiD;QAIjDH,OAJiD;QAKjDM;MALiD,CAA5B,CAAvB;MAOAV,IAAI,CAACiB,QAAD,CAAJ;IACD,CATD,CASE,OAAOG,GAAP,EAAY;MACZpB,IAAI,CAACoB,GAAD,CAAJ;IACD;EACF,CAlCH;EAqCA5B,KAAK,CAACK,GAAN,CACE,mBADF,EAEEF,GAAG,CAAC,QAAD,CAFL,EAGE,gBAAgBG,GAAhB,EAAqCuB,GAArC,EAA2DrB,IAA3D,EAAgF;IAC9E,MAAM;MAAEsB,GAAF;MAAOC;IAAP,IAAoBzB,GAAG,CAACI,MAA9B;IACA,MAAMsB,KAAK,GAAG,IAAIC,eAAJ,EAAd;;IACA,IAAI;MACF,MAAMC,MAAM,GAAI,MAAMhC,OAAO,CAACiC,cAAR,CAAuBL,GAAvB,EAA4BC,QAA5B,EAAsC;QAC1DK,MAAM,EAAEJ,KAAK,CAACI,MAD4C,CAE1D;QACA;;MAH0D,CAAtC,CAAtB;MAMAF,MAAM,CAACG,EAAP,CAAU,gBAAV,EAA6BC,IAAD,IAAU;QACpCT,GAAG,CAACU,MAAJ,CAAWC,iBAAA,CAAYC,cAAvB,EAAuCH,IAAvC;MACD,CAFD;MAIAJ,MAAM,CAACQ,IAAP,CAAY,OAAZ,EAAsBd,GAAD,IAAS;QAC5BC,GAAG,CAACc,MAAJ,CAAWC,YAAX,CAAwBhB,GAAxB;QACApB,IAAI,CAACoB,GAAD,CAAJ;MACD,CAHD;MAKAtB,GAAG,CAAC+B,EAAJ,CAAO,OAAP,EAAgB,MAAM;QACpBvC,KAAK,CAAC,wBAAD,EAA2BQ,GAAG,CAACuC,GAA/B,CAAL;QACAb,KAAK,CAACA,KAAN;MACD,CAHD;MAKAH,GAAG,CAACU,MAAJ,CAAWO,aAAA,CAAQC,YAAnB,EAAiCD,aAAA,CAAQE,YAAzC;MACAd,MAAM,CAACe,IAAP,CAAYpB,GAAZ;IACD,CAvBD,CAuBE,OAAOD,GAAP,EAAiB;MACjB;MACAC,GAAG,CAACc,MAAJ,CAAWC,YAAX,CAAwBhB,GAAxB;MACApB,IAAI,CAACoB,GAAD,CAAJ;IACD;EACF,CAlCH;AAoCD"}
1
+ {"version":3,"file":"package.js","names":["debug","buildDebug","route","auth","storage","can","allow","get","req","_res","next","name","params","package","version","write","query","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","pkg","filename","abort","AbortController","stream","getTarballNext","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 { IAuth } from '@verdaccio/auth';\nimport { HEADERS, HEADER_TYPE, stringUtils } from '@verdaccio/core';\nimport { allow } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\nconst debug = buildDebug('verdaccio:api:package');\n\nexport default function (route: Router, auth: IAuth, storage: Storage): void {\n const can = allow(auth);\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 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 };\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 '/:pkg/-/:filename',\n can('access'),\n async function (req: $RequestExtend, res: $ResponseExtend, next): Promise<void> {\n const { pkg, filename } = req.params;\n const abort = new AbortController();\n try {\n const stream = (await storage.getTarballNext(pkg, 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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"}
@@ -80,4 +80,4 @@ import { Storage } from '@verdaccio/store';
80
80
  *
81
81
  */
82
82
  export default function publish(router: Router, auth: IAuth, storage: Storage): void;
83
- export declare function publishPackageNext(storage: Storage): any;
83
+ export declare function publishPackage(storage: Storage): any;
package/build/publish.js CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = publish;
7
- exports.publishPackageNext = publishPackageNext;
7
+ exports.publishPackage = publishPackage;
8
8
 
9
9
  var _debug = _interopRequireDefault(require("debug"));
10
10
 
@@ -101,11 +101,9 @@ const debug = (0, _debug.default)('verdaccio:api:publish');
101
101
  */
102
102
 
103
103
  function publish(router, auth, storage) {
104
- const can = (0, _middleware.allow)(auth); // publish (update manifest) v6
105
-
106
- router.put('/:package', can('publish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackageNext(storage)); // unpublish a pacakge v6
107
-
108
- router.put('/:package/-rev/:revision', can('unpublish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackageNext(storage));
104
+ const can = (0, _middleware.allow)(auth);
105
+ router.put('/:package', can('publish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackage(storage));
106
+ router.put('/:package/-rev/:revision', can('unpublish'), (0, _middleware.media)(_mime.default.getType('json')), _middleware.expectJson, publishPackage(storage));
109
107
  /**
110
108
  * Un-publishing an entire package.
111
109
  *
@@ -114,7 +112,6 @@ function publish(router, auth, storage) {
114
112
  * npm http fetch GET 304 http://localhost:4873/package-name?write=true 1076ms (from cache)
115
113
  * npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms
116
114
  */
117
- // v6
118
115
 
119
116
  router.delete('/:package/-rev/:revision', can('unpublish'), async function (req, res, next) {
120
117
  const packageName = req.params.package;
@@ -172,7 +169,7 @@ function publish(router, auth, storage) {
172
169
  });
173
170
  }
174
171
 
175
- function publishPackageNext(storage) {
172
+ function publishPackage(storage) {
176
173
  return async function (req, _res, next) {
177
174
  const ac = new AbortController();
178
175
  const packageName = req.params.package;
@@ -1 +1 @@
1
- {"version":3,"file":"publish.js","names":["debug","buildDebug","publish","router","auth","storage","can","allow","put","media","mime","getType","expectJson","publishPackageNext","delete","req","res","next","packageName","params","package","rev","revision","logger","removePackage","status","HTTP_STATUS","CREATED","ok","API_MESSAGE","PKG_REMOVED","err","filename","removeTarball","TARBALL_REMOVED","_res","ac","AbortController","metadata","body","updateManifest","name","signal","requestOptions","host","hostname","protocol","headers","PKG_CREATED","success"],"sources":["../src/publish.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport mime from 'mime';\n\nimport { IAuth } from '@verdaccio/auth';\nimport { API_MESSAGE, HTTP_STATUS } from '@verdaccio/core';\nimport { logger } from '@verdaccio/logger';\nimport { allow, expectJson, media } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\n// import star from './star';\n// import { isPublishablePackage, isRelatedToDeprecation } from './utils';\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: start a package depends of the publish and unpublish permissions, there is no\n * specific flag for star or un start.\n * The URL for star is similar to the unpublish (change package format)\n *\n * npm has no endpoint for star 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 */\nexport default function publish(router: Router, auth: IAuth, storage: Storage): void {\n const can = allow(auth);\n // publish (update manifest) v6\n router.put(\n '/:package',\n can('publish'),\n media(mime.getType('json')),\n expectJson,\n publishPackageNext(storage)\n );\n\n // unpublish a pacakge v6\n router.put(\n '/:package/-rev/:revision',\n can('unpublish'),\n media(mime.getType('json')),\n expectJson,\n publishPackageNext(storage)\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 // v6\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\n logger.debug({ packageName }, `unpublishing @{packageName}`);\n try {\n await storage.removePackage(packageName, rev);\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\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);\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 publishPackageNext(storage: Storage): 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\n try {\n debug('publishing %s', packageName);\n await storage.updateManifest(metadata, {\n name: packageName,\n revision,\n signal: ac.signal,\n requestOptions: {\n host: req.hostname,\n protocol: req.protocol,\n // @ts-ignore\n headers: req.headers,\n },\n });\n _res.status(HTTP_STATUS.CREATED);\n\n return next({\n // TODO: this could be also Package Updated based on the\n // action, deprecate, star, publish new version, or create a package\n // the message some return from the method\n ok: API_MESSAGE.PKG_CREATED,\n success: true,\n });\n } catch (err: any) {\n // TODO: review if we need the abort controller here\n next(err);\n }\n };\n}\n"],"mappings":";;;;;;;;AAAA;;AAEA;;AAGA;;AACA;;AACA;;;;AAKA;AACA;AAEA,MAAMA,KAAK,GAAG,IAAAC,cAAA,EAAW,uBAAX,CAAd;AAEA;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,OAAT,CAAiBC,MAAjB,EAAiCC,IAAjC,EAA8CC,OAA9C,EAAsE;EACnF,MAAMC,GAAG,GAAG,IAAAC,iBAAA,EAAMH,IAAN,CAAZ,CADmF,CAEnF;;EACAD,MAAM,CAACK,GAAP,CACE,WADF,EAEEF,GAAG,CAAC,SAAD,CAFL,EAGE,IAAAG,iBAAA,EAAMC,aAAA,CAAKC,OAAL,CAAa,MAAb,CAAN,CAHF,EAIEC,sBAJF,EAKEC,kBAAkB,CAACR,OAAD,CALpB,EAHmF,CAWnF;;EACAF,MAAM,CAACK,GAAP,CACE,0BADF,EAEEF,GAAG,CAAC,WAAD,CAFL,EAGE,IAAAG,iBAAA,EAAMC,aAAA,CAAKC,OAAL,CAAa,MAAb,CAAN,CAHF,EAIEC,sBAJF,EAKEC,kBAAkB,CAACR,OAAD,CALpB;EAQA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;EACE;;EACAF,MAAM,CAACW,MAAP,CACE,0BADF,EAEER,GAAG,CAAC,WAAD,CAFL,EAGE,gBAAgBS,GAAhB,EAAqCC,GAArC,EAA2DC,IAA3D,EAAmF;IACjF,MAAMC,WAAW,GAAGH,GAAG,CAACI,MAAJ,CAAWC,OAA/B;IACA,MAAMC,GAAG,GAAGN,GAAG,CAACI,MAAJ,CAAWG,QAAvB;;IAEAC,cAAA,CAAOvB,KAAP,CAAa;MAAEkB;IAAF,CAAb,EAA+B,6BAA/B;;IACA,IAAI;MACF,MAAMb,OAAO,CAACmB,aAAR,CAAsBN,WAAtB,EAAmCG,GAAnC,CAAN;MACArB,KAAK,CAAC,wBAAD,EAA2BkB,WAA3B,CAAL;MACAF,GAAG,CAACS,MAAJ,CAAWC,iBAAA,CAAYC,OAAvB;MACA,OAAOV,IAAI,CAAC;QAAEW,EAAE,EAAEC,iBAAA,CAAYC;MAAlB,CAAD,CAAX;IACD,CALD,CAKE,OAAOC,GAAP,EAAY;MACZ,OAAOd,IAAI,CAACc,GAAD,CAAX;IACD;EACF,CAhBH;EAmBA;AACF;AACA;AACA;;EACE5B,MAAM,CAACW,MAAP,CACE,sCADF,EAEER,GAAG,CAAC,WAAD,CAFL,EAGEA,GAAG,CAAC,SAAD,CAHL,EAIE,gBACES,GADF,EAEEC,GAFF,EAGEC,IAHF,EAIiB;IACf,MAAMC,WAAW,GAAGH,GAAG,CAACI,MAAJ,CAAWC,OAA/B;IACA,MAAM;MAAEY,QAAF;MAAYV;IAAZ,IAAyBP,GAAG,CAACI,MAAnC;;IAEAI,cAAA,CAAOvB,KAAP,CACE;MAAEkB,WAAF;MAAec,QAAf;MAAyBV;IAAzB,CADF,EAEG,kEAFH;;IAIA,IAAI;MACF,MAAMjB,OAAO,CAAC4B,aAAR,CAAsBf,WAAtB,EAAmCc,QAAnC,EAA6CV,QAA7C,CAAN;MACAN,GAAG,CAACS,MAAJ,CAAWC,iBAAA,CAAYC,OAAvB;;MAEAJ,cAAA,CAAOvB,KAAP,CACE;QAAEkB,WAAF;QAAec,QAAf;QAAyBV;MAAzB,CADF,EAEG,sEAFH;;MAIA,OAAOL,IAAI,CAAC;QAAEW,EAAE,EAAEC,iBAAA,CAAYK;MAAlB,CAAD,CAAX;IACD,CATD,CASE,OAAOH,GAAP,EAAY;MACZ,OAAOd,IAAI,CAACc,GAAD,CAAX;IACD;EACF,CA5BH;AA8BD;;AAEM,SAASlB,kBAAT,CAA4BR,OAA5B,EAAmD;EACxD,OAAO,gBACLU,GADK,EAELoB,IAFK,EAGLlB,IAHK,EAIU;IACf,MAAMmB,EAAE,GAAG,IAAIC,eAAJ,EAAX;IACA,MAAMnB,WAAW,GAAGH,GAAG,CAACI,MAAJ,CAAWC,OAA/B;IACA,MAAM;MAAEE;IAAF,IAAeP,GAAG,CAACI,MAAzB;IACA,MAAMmB,QAAQ,GAAGvB,GAAG,CAACwB,IAArB;;IAEA,IAAI;MACFvC,KAAK,CAAC,eAAD,EAAkBkB,WAAlB,CAAL;MACA,MAAMb,OAAO,CAACmC,cAAR,CAAuBF,QAAvB,EAAiC;QACrCG,IAAI,EAAEvB,WAD+B;QAErCI,QAFqC;QAGrCoB,MAAM,EAAEN,EAAE,CAACM,MAH0B;QAIrCC,cAAc,EAAE;UACdC,IAAI,EAAE7B,GAAG,CAAC8B,QADI;UAEdC,QAAQ,EAAE/B,GAAG,CAAC+B,QAFA;UAGd;UACAC,OAAO,EAAEhC,GAAG,CAACgC;QAJC;MAJqB,CAAjC,CAAN;;MAWAZ,IAAI,CAACV,MAAL,CAAYC,iBAAA,CAAYC,OAAxB;;MAEA,OAAOV,IAAI,CAAC;QACV;QACA;QACA;QACAW,EAAE,EAAEC,iBAAA,CAAYmB,WAJN;QAKVC,OAAO,EAAE;MALC,CAAD,CAAX;IAOD,CAtBD,CAsBE,OAAOlB,GAAP,EAAiB;MACjB;MACAd,IAAI,CAACc,GAAD,CAAJ;IACD;EACF,CApCD;AAqCD"}
1
+ {"version":3,"file":"publish.js","names":["debug","buildDebug","publish","router","auth","storage","can","allow","put","media","mime","getType","expectJson","publishPackage","delete","req","res","next","packageName","params","package","rev","revision","logger","removePackage","status","HTTP_STATUS","CREATED","ok","API_MESSAGE","PKG_REMOVED","err","filename","removeTarball","TARBALL_REMOVED","_res","ac","AbortController","metadata","body","updateManifest","name","signal","requestOptions","host","hostname","protocol","headers","PKG_CREATED","success"],"sources":["../src/publish.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport mime from 'mime';\n\nimport { IAuth } from '@verdaccio/auth';\nimport { API_MESSAGE, HTTP_STATUS } from '@verdaccio/core';\nimport { logger } from '@verdaccio/logger';\nimport { allow, expectJson, media } from '@verdaccio/middleware';\nimport { Storage } from '@verdaccio/store';\n\nimport { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';\n\n// import star from './star';\n// import { isPublishablePackage, isRelatedToDeprecation } from './utils';\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: start a package depends of the publish and unpublish permissions, there is no\n * specific flag for star or un start.\n * The URL for star is similar to the unpublish (change package format)\n *\n * npm has no endpoint for star 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 */\nexport default function publish(router: Router, auth: IAuth, storage: Storage): void {\n const can = allow(auth);\n router.put(\n '/:package',\n can('publish'),\n media(mime.getType('json')),\n expectJson,\n publishPackage(storage)\n );\n\n router.put(\n '/:package/-rev/:revision',\n can('unpublish'),\n media(mime.getType('json')),\n expectJson,\n publishPackage(storage)\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\n logger.debug({ packageName }, `unpublishing @{packageName}`);\n try {\n await storage.removePackage(packageName, rev);\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\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);\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): 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\n try {\n debug('publishing %s', packageName);\n await storage.updateManifest(metadata, {\n name: packageName,\n revision,\n signal: ac.signal,\n requestOptions: {\n host: req.hostname,\n protocol: req.protocol,\n // @ts-ignore\n headers: req.headers,\n },\n });\n _res.status(HTTP_STATUS.CREATED);\n\n return next({\n // TODO: this could be also Package Updated based on the\n // action, deprecate, star, publish new version, or create a package\n // the message some return from the method\n ok: API_MESSAGE.PKG_CREATED,\n success: true,\n });\n } catch (err: any) {\n // TODO: review if we need the abort controller here\n next(err);\n }\n };\n}\n"],"mappings":"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"}
package/build/user.js CHANGED
@@ -7,8 +7,6 @@ exports.default = _default;
7
7
 
8
8
  var _debug = _interopRequireDefault(require("debug"));
9
9
 
10
- var _lodash = _interopRequireDefault(require("lodash"));
11
-
12
10
  var _auth = require("@verdaccio/auth");
13
11
 
14
12
  var _config = require("@verdaccio/config");
@@ -52,14 +50,16 @@ function _default(route, auth, config) {
52
50
  */
53
51
 
54
52
  route.put('/-/user/:org_couchdb_user/:_rev?/:revision?', function (req, res, next) {
53
+ var _req$remote_user;
54
+
55
55
  const {
56
56
  name,
57
57
  password
58
58
  } = req.body;
59
59
  debug('login or adduser');
60
- const remoteName = req.remote_user.name;
60
+ const remoteName = req === null || req === void 0 ? void 0 : (_req$remote_user = req.remote_user) === null || _req$remote_user === void 0 ? void 0 : _req$remote_user.name;
61
61
 
62
- if (_lodash.default.isNil(remoteName) === false && _lodash.default.isNil(name) === false && remoteName === name) {
62
+ if (typeof remoteName !== 'undefined' && typeof name === 'string' && remoteName === name) {
63
63
  debug('login: no remote user detected');
64
64
  auth.authenticate(name, password, async function callbackAuthenticate(err, user) {
65
65
  if (err) {
@@ -88,10 +88,12 @@ function _default(route, auth, config) {
88
88
  });
89
89
  });
90
90
  } else {
91
- if ((0, _utils.validatePassword)(password) === false) {
91
+ var _config$serverSetting;
92
+
93
+ if (_core.validatioUtils.validatePassword(password, config === null || config === void 0 ? void 0 : (_config$serverSetting = config.serverSettings) === null || _config$serverSetting === void 0 ? void 0 : _config$serverSetting.passwordValidationRegex) === false) {
92
94
  debug('adduser: invalid password'); // eslint-disable-next-line new-cap
93
95
 
94
- return next(_core.errorUtils.getCode(_core.HTTP_STATUS.BAD_REQUEST, _core.API_ERROR.PASSWORD_SHORT()));
96
+ return next(_core.errorUtils.getCode(_core.HTTP_STATUS.BAD_REQUEST, _core.API_ERROR.PASSWORD_SHORT));
95
97
  }
96
98
 
97
99
  auth.add_user(name, password, async function (err, user) {
@@ -108,7 +110,10 @@ function _default(route, auth, config) {
108
110
  }
109
111
 
110
112
  const token = name && password ? await (0, _auth.getApiToken)(auth, config, user, password) : undefined;
111
- debug('adduser: new token %o', (0, _utils.mask)(token, 4));
113
+
114
+ if (token) {
115
+ debug('adduser: new token %o', (0, _utils.mask)(token, 4));
116
+ }
112
117
 
113
118
  if (!token) {
114
119
  return next(_core.errorUtils.getUnauthorized());
package/build/user.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"user.js","names":["debug","buildDebug","route","auth","config","get","req","res","next","message","getAuthenticatedMessage","remote_user","name","status","HTTP_STATUS","OK","ok","put","password","body","remoteName","_","isNil","authenticate","callbackAuthenticate","err","user","logger","trace","errorUtils","getCode","UNAUTHORIZED","API_ERROR","BAD_USERNAME_PASSWORD","restoredRemoteUser","createRemoteUser","groups","token","getApiToken","getUnauthorized","CREATED","validatePassword","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';\nimport _ from 'lodash';\n\nimport { getApiToken } from '@verdaccio/auth';\nimport { IAuth } from '@verdaccio/auth';\nimport { createRemoteUser } from '@verdaccio/config';\nimport { API_ERROR, API_MESSAGE, HTTP_STATUS, errorUtils } from '@verdaccio/core';\nimport { logger } from '@verdaccio/logger';\nimport { Config, RemoteUser } from '@verdaccio/types';\nimport { getAuthenticatedMessage, mask, validatePassword } from '@verdaccio/utils';\n\nimport { $NextFunctionVer, $RequestExtend } from '../types/custom';\n\nconst debug = buildDebug('verdaccio:api:user');\n\nexport default function (route: Router, auth: IAuth, config: Config): void {\n route.get(\n '/-/user/:org_couchdb_user',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n debug('verifying user');\n const message = getAuthenticatedMessage(req.remote_user.name);\n debug('user authenticated message %o', message);\n res.status(HTTP_STATUS.OK);\n next({\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 {IAuth} auth\n * @param {Config} config\n */\n route.put(\n '/-/user/:org_couchdb_user/:_rev?/:revision?',\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 (_.isNil(remoteName) === false && _.isNil(name) === false && 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\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 if (validatePassword(password) === false) {\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 ? await getApiToken(auth, config, user, password) : undefined;\n debug('adduser: new token %o', mask(token as string, 4));\n if (!token) {\n return next(errorUtils.getUnauthorized());\n }\n\n req.remote_user = user;\n res.status(HTTP_STATUS.CREATED);\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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"}
1
+ {"version":3,"file":"user.js","names":["debug","buildDebug","route","auth","config","get","req","res","next","message","getAuthenticatedMessage","remote_user","name","status","HTTP_STATUS","OK","ok","put","password","body","remoteName","authenticate","callbackAuthenticate","err","user","logger","trace","errorUtils","getCode","UNAUTHORIZED","API_ERROR","BAD_USERNAME_PASSWORD","restoredRemoteUser","createRemoteUser","groups","token","getApiToken","getUnauthorized","CREATED","validatioUtils","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 { IAuth } from '@verdaccio/auth';\nimport { createRemoteUser } from '@verdaccio/config';\nimport { API_ERROR, API_MESSAGE, HTTP_STATUS, errorUtils, validatioUtils } from '@verdaccio/core';\nimport { logger } from '@verdaccio/logger';\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: IAuth, config: Config): void {\n route.get(\n '/-/user/:org_couchdb_user',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n debug('verifying user');\n const message = getAuthenticatedMessage(req.remote_user.name);\n debug('user authenticated message %o', message);\n res.status(HTTP_STATUS.OK);\n next({\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 {IAuth} auth\n * @param {Config} config\n */\n route.put(\n '/-/user/:org_couchdb_user/:_rev?/:revision?',\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 (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\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 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 ? await getApiToken(auth, config, user, password) : 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 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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"}
@@ -1,5 +1,6 @@
1
1
  import { Router } from 'express';
2
2
  import { IAuth } from '@verdaccio/auth';
3
+ import { Config } from '@verdaccio/types';
3
4
  export interface Profile {
4
5
  tfa: boolean;
5
6
  name: string;
@@ -10,4 +11,4 @@ export interface Profile {
10
11
  cidr_whitelist: string[] | null;
11
12
  fullname: string;
12
13
  }
13
- export default function (route: Router, auth: IAuth): void;
14
+ export default function (route: Router, auth: IAuth, config: Config): void;
@@ -9,11 +9,9 @@ var _lodash = _interopRequireDefault(require("lodash"));
9
9
 
10
10
  var _core = require("@verdaccio/core");
11
11
 
12
- var _utils = require("@verdaccio/utils");
13
-
14
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
13
 
16
- function _default(route, auth) {
14
+ function _default(route, auth, config) {
17
15
  function buildProfile(name) {
18
16
  return {
19
17
  tfa: false,
@@ -54,9 +52,11 @@ function _default(route, auth) {
54
52
  } = req.remote_user;
55
53
 
56
54
  if (_lodash.default.isNil(password) === false) {
57
- if ((0, _utils.validatePassword)(password.new) === false) {
55
+ var _config$serverSetting;
56
+
57
+ if (_core.validatioUtils.validatePassword(password.new, config === null || config === void 0 ? void 0 : (_config$serverSetting = config.serverSettings) === null || _config$serverSetting === void 0 ? void 0 : _config$serverSetting.passwordValidationRegex) === false) {
58
58
  /* eslint new-cap:off */
59
- return next(_core.errorUtils.getCode(_core.HTTP_STATUS.UNAUTHORIZED, _core.API_ERROR.PASSWORD_SHORT()));
59
+ return next(_core.errorUtils.getCode(_core.HTTP_STATUS.UNAUTHORIZED, _core.API_ERROR.PASSWORD_SHORT));
60
60
  /* eslint new-cap:off */
61
61
  }
62
62
 
@@ -1 +1 @@
1
- {"version":3,"file":"profile.js","names":["route","auth","buildProfile","name","tfa","email","email_verified","created","updated","cidr_whitelist","fullname","get","req","res","next","_","isNil","remote_user","status","HTTP_STATUS","UNAUTHORIZED","message","API_ERROR","MUST_BE_LOGGED","post","password","body","validatePassword","new","errorUtils","getCode","PASSWORD_SHORT","changePassword","old","err","isUpdated","isNull","getConflict","getInternalError","INTERNAL_SERVER_ERROR","SERVICE_UNAVAILABLE","SUPPORT_ERRORS","TFA_DISABLED","INTERNAL_ERROR","APP_ERROR","PROFILE_ERROR"],"sources":["../../src/v1/profile.ts"],"sourcesContent":["import { Response, Router } from 'express';\nimport _ from 'lodash';\n\nimport { IAuth } from '@verdaccio/auth';\nimport { API_ERROR, APP_ERROR, HTTP_STATUS, SUPPORT_ERRORS, errorUtils } from '@verdaccio/core';\nimport { validatePassword } from '@verdaccio/utils';\n\nimport { $NextFunctionVer, $RequestExtend } from '../../types/custom';\n\nexport interface Profile {\n tfa: boolean;\n name: string;\n email: string;\n email_verified: boolean;\n created: string;\n updated: string;\n cidr_whitelist: string[] | null;\n fullname: string;\n}\n\nexport default function (route: Router, auth: IAuth): void {\n function buildProfile(name: string): Profile {\n return {\n tfa: false,\n name,\n email: '',\n email_verified: false,\n created: '',\n updated: '',\n cidr_whitelist: null,\n fullname: '',\n };\n }\n\n route.get(\n '/-/npm/v1/user',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name) === false) {\n return next(buildProfile(req.remote_user.name));\n }\n\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n );\n\n route.post(\n '/-/npm/v1/user',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name)) {\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n\n const { password, tfa } = req.body;\n const { name } = req.remote_user;\n\n if (_.isNil(password) === false) {\n if (validatePassword(password.new) === false) {\n /* eslint new-cap:off */\n return next(errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT()));\n /* eslint new-cap:off */\n }\n\n auth.changePassword(\n name,\n password.old,\n password.new,\n (err, isUpdated): $NextFunctionVer => {\n if (_.isNull(err) === false) {\n return next(\n errorUtils.getCode(err.status, err.message) || errorUtils.getConflict(err.message)\n );\n }\n\n if (isUpdated) {\n return next(buildProfile(req.remote_user.name));\n }\n return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));\n }\n );\n } else if (_.isNil(tfa) === false) {\n return next(\n errorUtils.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.TFA_DISABLED)\n );\n } else {\n return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, APP_ERROR.PROFILE_ERROR));\n }\n }\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"profile.js","names":["route","auth","config","buildProfile","name","tfa","email","email_verified","created","updated","cidr_whitelist","fullname","get","req","res","next","_","isNil","remote_user","status","HTTP_STATUS","UNAUTHORIZED","message","API_ERROR","MUST_BE_LOGGED","post","password","body","validatioUtils","validatePassword","new","serverSettings","passwordValidationRegex","errorUtils","getCode","PASSWORD_SHORT","changePassword","old","err","isUpdated","isNull","getConflict","getInternalError","INTERNAL_SERVER_ERROR","SERVICE_UNAVAILABLE","SUPPORT_ERRORS","TFA_DISABLED","INTERNAL_ERROR","APP_ERROR","PROFILE_ERROR"],"sources":["../../src/v1/profile.ts"],"sourcesContent":["import { Response, Router } from 'express';\nimport _ from 'lodash';\n\nimport { IAuth } from '@verdaccio/auth';\nimport {\n API_ERROR,\n APP_ERROR,\n HTTP_STATUS,\n SUPPORT_ERRORS,\n errorUtils,\n validatioUtils,\n} from '@verdaccio/core';\nimport { Config } from '@verdaccio/types';\n\nimport { $NextFunctionVer, $RequestExtend } from '../../types/custom';\n\nexport interface Profile {\n tfa: boolean;\n name: string;\n email: string;\n email_verified: boolean;\n created: string;\n updated: string;\n cidr_whitelist: string[] | null;\n fullname: string;\n}\n\nexport default function (route: Router, auth: IAuth, config: Config): void {\n function buildProfile(name: string): Profile {\n return {\n tfa: false,\n name,\n email: '',\n email_verified: false,\n created: '',\n updated: '',\n cidr_whitelist: null,\n fullname: '',\n };\n }\n\n route.get(\n '/-/npm/v1/user',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name) === false) {\n return next(buildProfile(req.remote_user.name));\n }\n\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n );\n\n route.post(\n '/-/npm/v1/user',\n function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name)) {\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n\n const { password, tfa } = req.body;\n const { name } = req.remote_user;\n\n if (_.isNil(password) === false) {\n if (\n validatioUtils.validatePassword(\n password.new,\n config?.serverSettings?.passwordValidationRegex\n ) === false\n ) {\n /* eslint new-cap:off */\n return next(errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT));\n /* eslint new-cap:off */\n }\n\n auth.changePassword(\n name,\n password.old,\n password.new,\n (err, isUpdated): $NextFunctionVer => {\n if (_.isNull(err) === false) {\n return next(\n errorUtils.getCode(err.status, err.message) || errorUtils.getConflict(err.message)\n );\n }\n\n if (isUpdated) {\n return next(buildProfile(req.remote_user.name));\n }\n return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));\n }\n );\n } else if (_.isNil(tfa) === false) {\n return next(\n errorUtils.getCode(HTTP_STATUS.SERVICE_UNAVAILABLE, SUPPORT_ERRORS.TFA_DISABLED)\n );\n } else {\n return next(errorUtils.getCode(HTTP_STATUS.INTERNAL_ERROR, APP_ERROR.PROFILE_ERROR));\n }\n }\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/api",
3
- "version": "6.0.0-6-next.29",
3
+ "version": "6.0.0-6-next.31",
4
4
  "description": "loaders logic",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -30,13 +30,13 @@
30
30
  },
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@verdaccio/auth": "6.0.0-6-next.25",
34
- "@verdaccio/config": "6.0.0-6-next.17",
35
- "@verdaccio/core": "6.0.0-6-next.8",
36
- "@verdaccio/logger": "6.0.0-6-next.14",
37
- "@verdaccio/middleware": "6.0.0-6-next.25",
38
- "@verdaccio/store": "6.0.0-6-next.26",
39
- "@verdaccio/utils": "6.0.0-6-next.14",
33
+ "@verdaccio/auth": "6.0.0-6-next.27",
34
+ "@verdaccio/config": "6.0.0-6-next.48",
35
+ "@verdaccio/core": "6.0.0-6-next.48",
36
+ "@verdaccio/logger": "6.0.0-6-next.16",
37
+ "@verdaccio/middleware": "6.0.0-6-next.27",
38
+ "@verdaccio/store": "6.0.0-6-next.28",
39
+ "@verdaccio/utils": "6.0.0-6-next.16",
40
40
  "abortcontroller-polyfill": "1.7.3",
41
41
  "cookies": "0.8.0",
42
42
  "debug": "4.3.4",
@@ -47,10 +47,10 @@
47
47
  "semver": "7.3.7"
48
48
  },
49
49
  "devDependencies": {
50
- "@types/node": "16.11.56",
51
- "@verdaccio/server": "6.0.0-6-next.35",
52
- "@verdaccio/types": "11.0.0-6-next.16",
53
- "@verdaccio/test-helper": "1.1.0-6-next.4",
50
+ "@types/node": "16.11.60",
51
+ "@verdaccio/server": "6.0.0-6-next.37",
52
+ "@verdaccio/types": "11.0.0-6-next.17",
53
+ "@verdaccio/test-helper": "2.0.0-6-next.5",
54
54
  "supertest": "6.2.4",
55
55
  "nock": "13.2.9",
56
56
  "mockdate": "3.0.5"
package/src/index.ts CHANGED
@@ -52,7 +52,7 @@ export default function (config: Config, auth: IAuth, storage: Storage): Router
52
52
  // for "npm whoami"
53
53
  whoami(app);
54
54
  pkg(app, auth, storage);
55
- profile(app, auth);
55
+ profile(app, auth, config);
56
56
  // @deprecated endpoint, 404 by default
57
57
  search(app);
58
58
  user(app, auth, config);
package/src/package.ts CHANGED
@@ -2,7 +2,7 @@ import buildDebug from 'debug';
2
2
  import { Router } from 'express';
3
3
 
4
4
  import { IAuth } from '@verdaccio/auth';
5
- import { HEADERS, HEADER_TYPE } from '@verdaccio/core';
5
+ import { HEADERS, HEADER_TYPE, stringUtils } from '@verdaccio/core';
6
6
  import { allow } from '@verdaccio/middleware';
7
7
  import { Storage } from '@verdaccio/store';
8
8
 
@@ -25,7 +25,8 @@ export default function (route: Router, auth: IAuth, storage: Storage): void {
25
25
  const name = req.params.package;
26
26
  let version = req.params.version;
27
27
  const write = req.query.write === 'true';
28
- const abbreviated = req.get('Accept') === Storage.ABBREVIATED_HEADER;
28
+ const abbreviated =
29
+ stringUtils.getByQualityPriorityValue(req.get('Accept')) === Storage.ABBREVIATED_HEADER;
29
30
  const requestOptions = {
30
31
  protocol: req.protocol,
31
32
  headers: req.headers as any,
@@ -43,6 +44,12 @@ export default function (route: Router, auth: IAuth, storage: Storage): void {
43
44
  version,
44
45
  requestOptions,
45
46
  });
47
+ if (abbreviated) {
48
+ _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET);
49
+ } else {
50
+ _res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
51
+ }
52
+
46
53
  next(manifest);
47
54
  } catch (err) {
48
55
  next(err);
package/src/publish.ts CHANGED
@@ -95,22 +95,20 @@ const debug = buildDebug('verdaccio:api:publish');
95
95
  */
96
96
  export default function publish(router: Router, auth: IAuth, storage: Storage): void {
97
97
  const can = allow(auth);
98
- // publish (update manifest) v6
99
98
  router.put(
100
99
  '/:package',
101
100
  can('publish'),
102
101
  media(mime.getType('json')),
103
102
  expectJson,
104
- publishPackageNext(storage)
103
+ publishPackage(storage)
105
104
  );
106
105
 
107
- // unpublish a pacakge v6
108
106
  router.put(
109
107
  '/:package/-rev/:revision',
110
108
  can('unpublish'),
111
109
  media(mime.getType('json')),
112
110
  expectJson,
113
- publishPackageNext(storage)
111
+ publishPackage(storage)
114
112
  );
115
113
 
116
114
  /**
@@ -121,7 +119,6 @@ export default function publish(router: Router, auth: IAuth, storage: Storage):
121
119
  * npm http fetch GET 304 http://localhost:4873/package-name?write=true 1076ms (from cache)
122
120
  * npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms
123
121
  */
124
- // v6
125
122
  router.delete(
126
123
  '/:package/-rev/:revision',
127
124
  can('unpublish'),
@@ -177,7 +174,7 @@ export default function publish(router: Router, auth: IAuth, storage: Storage):
177
174
  );
178
175
  }
179
176
 
180
- export function publishPackageNext(storage: Storage): any {
177
+ export function publishPackage(storage: Storage): any {
181
178
  return async function (
182
179
  req: $RequestExtend,
183
180
  _res: $ResponseExtend,
package/src/user.ts CHANGED
@@ -1,14 +1,13 @@
1
1
  import buildDebug from 'debug';
2
2
  import { Response, Router } from 'express';
3
- import _ from 'lodash';
4
3
 
5
4
  import { getApiToken } from '@verdaccio/auth';
6
5
  import { IAuth } from '@verdaccio/auth';
7
6
  import { createRemoteUser } from '@verdaccio/config';
8
- import { API_ERROR, API_MESSAGE, HTTP_STATUS, errorUtils } from '@verdaccio/core';
7
+ import { API_ERROR, API_MESSAGE, HTTP_STATUS, errorUtils, validatioUtils } from '@verdaccio/core';
9
8
  import { logger } from '@verdaccio/logger';
10
9
  import { Config, RemoteUser } from '@verdaccio/types';
11
- import { getAuthenticatedMessage, mask, validatePassword } from '@verdaccio/utils';
10
+ import { getAuthenticatedMessage, mask } from '@verdaccio/utils';
12
11
 
13
12
  import { $NextFunctionVer, $RequestExtend } from '../types/custom';
14
13
 
@@ -50,9 +49,9 @@ export default function (route: Router, auth: IAuth, config: Config): void {
50
49
  function (req: $RequestExtend, res: Response, next: $NextFunctionVer): void {
51
50
  const { name, password } = req.body;
52
51
  debug('login or adduser');
53
- const remoteName = req.remote_user.name;
52
+ const remoteName = req?.remote_user?.name;
54
53
 
55
- if (_.isNil(remoteName) === false && _.isNil(name) === false && remoteName === name) {
54
+ if (typeof remoteName !== 'undefined' && typeof name === 'string' && remoteName === name) {
56
55
  debug('login: no remote user detected');
57
56
  auth.authenticate(
58
57
  name,
@@ -87,10 +86,15 @@ export default function (route: Router, auth: IAuth, config: Config): void {
87
86
  }
88
87
  );
89
88
  } else {
90
- if (validatePassword(password) === false) {
89
+ if (
90
+ validatioUtils.validatePassword(
91
+ password,
92
+ config?.serverSettings?.passwordValidationRegex
93
+ ) === false
94
+ ) {
91
95
  debug('adduser: invalid password');
92
96
  // eslint-disable-next-line new-cap
93
- return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT()));
97
+ return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.PASSWORD_SHORT));
94
98
  }
95
99
 
96
100
  auth.add_user(name, password, async function (err, user): Promise<void> {
@@ -109,7 +113,9 @@ export default function (route: Router, auth: IAuth, config: Config): void {
109
113
 
110
114
  const token =
111
115
  name && password ? await getApiToken(auth, config, user, password) : undefined;
112
- debug('adduser: new token %o', mask(token as string, 4));
116
+ if (token) {
117
+ debug('adduser: new token %o', mask(token as string, 4));
118
+ }
113
119
  if (!token) {
114
120
  return next(errorUtils.getUnauthorized());
115
121
  }
package/src/v1/profile.ts CHANGED
@@ -2,8 +2,15 @@ import { Response, Router } from 'express';
2
2
  import _ from 'lodash';
3
3
 
4
4
  import { IAuth } from '@verdaccio/auth';
5
- import { API_ERROR, APP_ERROR, HTTP_STATUS, SUPPORT_ERRORS, errorUtils } from '@verdaccio/core';
6
- import { validatePassword } from '@verdaccio/utils';
5
+ import {
6
+ API_ERROR,
7
+ APP_ERROR,
8
+ HTTP_STATUS,
9
+ SUPPORT_ERRORS,
10
+ errorUtils,
11
+ validatioUtils,
12
+ } from '@verdaccio/core';
13
+ import { Config } from '@verdaccio/types';
7
14
 
8
15
  import { $NextFunctionVer, $RequestExtend } from '../../types/custom';
9
16
 
@@ -18,7 +25,7 @@ export interface Profile {
18
25
  fullname: string;
19
26
  }
20
27
 
21
- export default function (route: Router, auth: IAuth): void {
28
+ export default function (route: Router, auth: IAuth, config: Config): void {
22
29
  function buildProfile(name: string): Profile {
23
30
  return {
24
31
  tfa: false,
@@ -60,9 +67,14 @@ export default function (route: Router, auth: IAuth): void {
60
67
  const { name } = req.remote_user;
61
68
 
62
69
  if (_.isNil(password) === false) {
63
- if (validatePassword(password.new) === false) {
70
+ if (
71
+ validatioUtils.validatePassword(
72
+ password.new,
73
+ config?.serverSettings?.passwordValidationRegex
74
+ ) === false
75
+ ) {
64
76
  /* eslint new-cap:off */
65
- return next(errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT()));
77
+ return next(errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, API_ERROR.PASSWORD_SHORT));
66
78
  /* eslint new-cap:off */
67
79
  }
68
80
 
@@ -27,7 +27,8 @@ export const getConf = (conf) => {
27
27
  };
28
28
 
29
29
  export async function initializeServer(configName): Promise<Application> {
30
- return initializeServerHelper(getConf(configName), [apiMiddleware], Storage);
30
+ const config = getConf(configName);
31
+ return initializeServerHelper(config, [apiMiddleware], Storage);
31
32
  }
32
33
 
33
34
  export function createUser(app, name: string, password: string): supertest.Test {
@@ -90,7 +90,7 @@ describe('package', () => {
90
90
  .get(`/${pkg}`)
91
91
  .set(HEADERS.ACCEPT, HEADERS.JSON)
92
92
  .set(HEADERS.ACCEPT, Storage.ABBREVIATED_HEADER)
93
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
93
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET)
94
94
  .expect(HTTP_STATUS.OK);
95
95
  expect(response.body.name).toEqual(pkg);
96
96
  expect(response.body.time).toBeDefined();
@@ -22,6 +22,9 @@ jest.mock('@verdaccio/auth', () => ({
22
22
  apiJWTmiddleware() {
23
23
  return mockApiJWTmiddleware();
24
24
  }
25
+ init() {
26
+ return Promise.resolve();
27
+ }
25
28
  allow_access(_d, f_, cb) {
26
29
  cb(null, true);
27
30
  }
@@ -1,264 +1,169 @@
1
- import _ from 'lodash';
2
1
  import supertest from 'supertest';
3
2
 
4
- import {
5
- API_ERROR,
6
- API_MESSAGE,
7
- HEADERS,
8
- HEADER_TYPE,
9
- HTTP_STATUS,
10
- errorUtils,
11
- } from '@verdaccio/core';
3
+ import { API_ERROR, HEADERS, HEADER_TYPE, HTTP_STATUS, TOKEN_BEARER } from '@verdaccio/core';
4
+ import { buildToken } from '@verdaccio/utils';
12
5
 
13
- import { $RequestExtend, $ResponseExtend } from '../../types/custom';
14
- import { initializeServer } from './_helper';
6
+ import { createUser, getPackage, initializeServer } from './_helper';
15
7
 
16
- const mockApiJWTmiddleware = jest.fn(
17
- () =>
18
- (req: $RequestExtend, res: $ResponseExtend, _next): void => {
19
- req.remote_user = { name: 'test', groups: [], real_groups: [] };
20
- _next();
21
- }
22
- );
8
+ const FORBIDDEN_VUE = 'authorization required to access package vue';
23
9
 
24
- const mockAuthenticate = jest.fn(() => (_name, _password, callback): void => {
25
- return callback(null, ['all']);
26
- });
10
+ jest.setTimeout(20000);
27
11
 
28
- const mockAddUser = jest.fn(() => (_name, _password, callback): void => {
29
- return callback(errorUtils.getConflict(API_ERROR.USERNAME_ALREADY_REGISTERED));
30
- });
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 app = await initializeServer(conf);
17
+ const credentials = { name: 'JotaJWT', password: 'secretPass' };
18
+ const response = await createUser(app, credentials.name, credentials.password);
19
+ expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
31
20
 
32
- jest.mock('@verdaccio/auth', () => ({
33
- getApiToken: () => 'token',
34
- Auth: class {
35
- apiJWTmiddleware() {
36
- return mockApiJWTmiddleware();
37
- }
38
- allow_access(_d, f_, cb) {
39
- cb(null, true);
40
- }
41
- add_user(name, password, callback) {
42
- mockAddUser()(name, password, callback);
43
- }
44
- authenticate(_name, _password, callback) {
45
- mockAuthenticate()(_name, _password, callback);
46
- }
47
- },
48
- }));
21
+ const vueResponse = await getPackage(app, response.body.token, 'vue');
22
+ expect(vueResponse.body).toBeDefined();
23
+ expect(vueResponse.body.name).toMatch('vue');
49
24
 
50
- // FIXME: This might be covered with user.jwt.spec
51
- describe('user', () => {
52
- const credentials = { name: 'test', password: 'test' };
25
+ const vueFailResp = await getPackage(app, FAKE_TOKEN, 'vue', HTTP_STATUS.UNAUTHORIZED);
26
+ expect(vueFailResp.body.error).toMatch(FORBIDDEN_VUE);
27
+ });
53
28
 
54
- test('should test add a new user', async () => {
55
- mockApiJWTmiddleware.mockImplementationOnce(
56
- () =>
57
- (req: $RequestExtend, res: $ResponseExtend, _next): void => {
58
- req.remote_user = { name: undefined };
59
- _next();
60
- }
61
- );
29
+ test.each([['user.yaml'], ['user.jwt.yaml']])('should login an user', async (conf) => {
30
+ const app = await initializeServer(conf);
31
+ const credentials = { name: 'test', password: 'test' };
32
+ const response = await createUser(app, credentials.name, credentials.password);
33
+ expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
62
34
 
63
- mockAddUser.mockImplementationOnce(() => (_name, _password, callback): void => {
64
- return callback(null, true);
65
- });
66
- const app = await initializeServer('user.yaml');
67
- return new Promise((resolve, reject) => {
68
- supertest(app)
69
- .put(`/-/user/org.couchdb.user:newUser`)
35
+ await supertest(app)
36
+ .put(`/-/user/org.couchdb.user:${credentials.name}`)
70
37
  .send({
71
- name: 'newUser',
72
- password: 'newUser',
38
+ name: credentials.name,
39
+ password: credentials.password,
73
40
  })
41
+ .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, response.body.token))
74
42
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
75
- .expect(HTTP_STATUS.CREATED)
76
- .end(function (err, res) {
77
- if (err) {
78
- return reject(err);
79
- }
80
- expect(res.body.ok).toBeDefined();
81
- expect(res.body.token).toBeDefined();
82
- const token = res.body.token;
83
- expect(typeof token).toBe('string');
84
- expect(res.body.ok).toMatch(`user 'newUser' created`);
85
- resolve(null);
86
- });
43
+ .expect(HTTP_STATUS.CREATED);
87
44
  });
88
- });
89
45
 
90
- test('should test fails on add a existing user with login', async () => {
91
- mockApiJWTmiddleware.mockImplementationOnce(
92
- () =>
93
- (req: $RequestExtend, res: $ResponseExtend, _next): void => {
94
- req.remote_user = { name: undefined };
95
- _next();
96
- }
46
+ test.each([['user.yaml'], ['user.jwt.yaml']])(
47
+ 'should fails login a valid user',
48
+ async (conf) => {
49
+ const app = await initializeServer(conf);
50
+ const credentials = { name: 'test', password: 'test' };
51
+ const response = await createUser(app, credentials.name, credentials.password);
52
+ expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
53
+
54
+ await supertest(app)
55
+ .put(`/-/user/org.couchdb.user:${credentials.name}`)
56
+ .send({
57
+ name: credentials.name,
58
+ password: 'failPassword',
59
+ })
60
+ .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, response.body.token))
61
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
62
+ .expect(HTTP_STATUS.UNAUTHORIZED);
63
+ }
97
64
  );
98
- const app = await initializeServer('user.yaml');
99
- return new Promise((resolve, reject) => {
100
- supertest(app)
101
- .put('/-/user/org.couchdb.user:jotaNew')
102
- .send(credentials)
103
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
104
- .expect(HTTP_STATUS.CONFLICT)
105
- .end(function (err, res) {
106
- if (err) {
107
- return reject(err);
108
- }
109
- expect(res.body.error).toBeDefined();
110
- expect(res.body.error).toMatch(API_ERROR.USERNAME_ALREADY_REGISTERED);
111
- resolve(res.body);
112
- });
113
- });
114
- });
115
65
 
116
- test('should log in as existing user', async () => {
117
- const app = await initializeServer('user.yaml');
118
- return new Promise((resolve, reject) => {
119
- supertest(app)
120
- .put(`/-/user/org.couchdb.user:${credentials.name}`)
121
- .send(credentials)
122
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
123
- .expect(HTTP_STATUS.CREATED)
124
- .end((err, res) => {
125
- if (err) {
126
- return reject(err);
127
- }
128
-
129
- expect(res.body).toBeTruthy();
130
- expect(res.body.ok).toMatch(`you are authenticated as \'${credentials.name}\'`);
131
- resolve(res);
132
- });
133
- });
134
- });
135
-
136
- test('should test fails add a new user with missing name', async () => {
137
- mockApiJWTmiddleware.mockImplementationOnce(
138
- () =>
139
- (req: $RequestExtend, res: $ResponseExtend, _next): void => {
140
- req.remote_user = { name: undefined };
141
- _next();
142
- }
66
+ test.each([['user.yaml'], ['user.jwt.yaml']])(
67
+ 'should test conflict create new user',
68
+ async (conf) => {
69
+ const app = await initializeServer(conf);
70
+ const credentials = { name: 'JotaJWT', password: 'secretPass' };
71
+ const response = await createUser(app, credentials.name, credentials.password);
72
+ expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
73
+ const response2 = await supertest(app)
74
+ .put(`/-/user/org.couchdb.user:${credentials.name}`)
75
+ .send({
76
+ name: credentials.name,
77
+ password: credentials.password,
78
+ })
79
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
80
+ .expect(HTTP_STATUS.CONFLICT);
81
+ expect(response2.body.error).toBe(API_ERROR.USERNAME_ALREADY_REGISTERED);
82
+ }
143
83
  );
144
- mockAddUser.mockImplementationOnce(() => (_name, _password, callback): void => {
145
- return callback(errorUtils.getBadRequest(API_ERROR.USERNAME_PASSWORD_REQUIRED));
146
- });
147
- const credentialsShort = _.cloneDeep(credentials);
148
- delete credentialsShort.name;
149
84
 
150
- const app = await initializeServer('user.yaml');
151
- return new Promise((resolve, reject) => {
152
- supertest(app)
153
- .put(`/-/user/org.couchdb.user:${credentials.name}`)
154
- .send(credentialsShort)
155
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
156
- .expect(HTTP_STATUS.BAD_REQUEST)
157
- .end(function (err, res) {
158
- if (err) {
159
- return reject(err);
160
- }
161
-
162
- expect(res.body.error).toBeDefined();
163
- expect(res.body.error).toMatch(API_ERROR.USERNAME_PASSWORD_REQUIRED);
164
- resolve(app);
165
- });
166
- });
167
- });
168
-
169
- test('should test fails add a new user with missing password', async () => {
170
- mockApiJWTmiddleware.mockImplementationOnce(
171
- () =>
172
- (req: $RequestExtend, res: $ResponseExtend, _next): void => {
173
- req.remote_user = { name: undefined };
174
- _next();
175
- }
85
+ test.each([['user.yaml'], ['user.jwt.yaml']])(
86
+ 'should fails on login if user credentials are invalid',
87
+ async (conf) => {
88
+ const app = await initializeServer(conf);
89
+ const credentials = { name: 'newFailsUser', password: 'secretPass' };
90
+ const response = await createUser(app, credentials.name, credentials.password);
91
+ expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
92
+ const response2 = await supertest(app)
93
+ .put(`/-/user/org.couchdb.user:${credentials.name}`)
94
+ .send({
95
+ name: credentials.name,
96
+ password: 'BAD_PASSWORD',
97
+ })
98
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
99
+ .expect(HTTP_STATUS.UNAUTHORIZED);
100
+ expect(response2.body.error).toBe(API_ERROR.UNAUTHORIZED_ACCESS);
101
+ }
176
102
  );
177
- const credentialsShort = _.cloneDeep(credentials);
178
- delete credentialsShort.password;
179
-
180
- const app = await initializeServer('user.yaml');
181
- return new Promise((resolve, reject) => {
182
- supertest(app)
183
- .put(`/-/user/org.couchdb.user:${credentials.name}`)
184
- .send(credentialsShort)
185
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
186
- .expect(HTTP_STATUS.BAD_REQUEST)
187
- .end(function (err, res) {
188
- if (err) {
189
- return reject(err);
190
- }
191
-
192
- expect(res.body.error).toBeDefined();
193
- // FIXME: message is not 100% accurate
194
- // eslint-disable-next-line new-cap
195
- expect(res.body.error).toMatch(API_ERROR.PASSWORD_SHORT());
196
- resolve(res);
197
- });
198
- });
199
- });
200
103
 
201
- test('should test fails add a new user with wrong password', async () => {
202
- mockApiJWTmiddleware.mockImplementationOnce(
203
- () =>
204
- (req: $RequestExtend, res: $ResponseExtend, _next): void => {
205
- req.remote_user = { name: 'test' };
206
- _next();
207
- }
104
+ test.each([['user.yaml'], ['user.jwt.yaml']])(
105
+ 'should fails password validation',
106
+ async (conf) => {
107
+ const credentials = { name: 'test', password: '12' };
108
+ const app = await initializeServer(conf);
109
+ const response = await supertest(app)
110
+ .put(`/-/user/org.couchdb.user:${credentials.name}`)
111
+ .send({
112
+ name: credentials.name,
113
+ password: credentials.password,
114
+ })
115
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
116
+ .expect(HTTP_STATUS.BAD_REQUEST);
117
+ expect(response.body.error).toBe(API_ERROR.PASSWORD_SHORT);
118
+ }
208
119
  );
209
- mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
210
- return callback(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
211
- });
212
- const credentialsShort = _.cloneDeep(credentials);
213
- credentialsShort.password = 'failPassword';
214
- const app = await initializeServer('user.yaml');
215
- return new Promise((resolve, reject) => {
216
- supertest(app)
217
- .put('/-/user/org.couchdb.user:test')
218
- .send(credentialsShort)
219
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
220
- .expect(HTTP_STATUS.UNAUTHORIZED)
221
- .end(function (err, res) {
222
- if (err) {
223
- return reject(err);
224
- }
225
120
 
226
- expect(res.body.error).toBeDefined();
227
- expect(res.body.error).toMatch(API_ERROR.BAD_USERNAME_PASSWORD);
228
- resolve(res);
229
- });
230
- });
231
- });
121
+ test.each([['user.yaml'], ['user.jwt.yaml']])(
122
+ 'should fails missing password validation',
123
+ async (conf) => {
124
+ const credentials = { name: 'test' };
125
+ const app = await initializeServer(conf);
126
+ const response = await supertest(app)
127
+ .put(`/-/user/org.couchdb.user:${credentials.name}`)
128
+ .send({
129
+ name: credentials.name,
130
+ password: undefined,
131
+ })
132
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
133
+ .expect(HTTP_STATUS.BAD_REQUEST);
134
+ expect(response.body.error).toBe(API_ERROR.PASSWORD_SHORT);
135
+ }
136
+ );
232
137
 
233
- test('should be able to logout an user', async () => {
234
- mockApiJWTmiddleware.mockImplementationOnce(
235
- () =>
236
- (req: $RequestExtend, _res: $ResponseExtend, _next): void => {
237
- req.remote_user = { name: 'test' };
238
- _next();
239
- }
138
+ test.each([['user.yaml'], ['user.jwt.yaml']])(
139
+ 'should verify if user is logged',
140
+ async (conf) => {
141
+ const app = await initializeServer(conf);
142
+ const credentials = { name: 'jota', password: 'secretPass' };
143
+ const response = await createUser(app, credentials.name, credentials.password);
144
+ expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
145
+ const response2 = await supertest(app)
146
+ .get(`/-/user/org.couchdb.user:${credentials.name}`)
147
+ .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, response.body.token))
148
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
149
+ .expect(HTTP_STATUS.OK);
150
+ expect(response2.body.ok).toBe(`you are authenticated as '${credentials.name}'`);
151
+ }
240
152
  );
241
- mockAuthenticate.mockImplementationOnce(() => (_name, _password, callback): void => {
242
- return callback(errorUtils.getUnauthorized(API_ERROR.BAD_USERNAME_PASSWORD));
243
- });
244
- const credentialsShort = _.cloneDeep(credentials);
245
- credentialsShort.password = 'failPassword';
246
153
 
247
- const app = await initializeServer('user.yaml');
248
- return new Promise((resolve, reject) => {
249
- supertest(app)
250
- .delete('/-/user/token/someSecretToken')
251
- .send(credentialsShort)
154
+ test.each([['user.yaml'], ['user.jwt.yaml']])('should logout user', async (conf) => {
155
+ const app = await initializeServer(conf);
156
+ const credentials = { name: 'jota', password: 'secretPass' };
157
+ const response = await createUser(app, credentials.name, credentials.password);
158
+ await supertest(app)
159
+ .get(`/-/user/org.couchdb.user:${credentials.name}`)
160
+ .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, response.body.token))
252
161
  .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
253
- .expect(HTTP_STATUS.OK)
254
- .end(function (err, res) {
255
- if (err) {
256
- return reject(err);
257
- }
258
-
259
- expect(res.body.ok).toMatch(API_MESSAGE.LOGGED_OUT);
260
- resolve(res);
261
- });
162
+ .expect(HTTP_STATUS.OK);
163
+ await supertest(app)
164
+ .delete(`/-/user/token/someSecretToken:${response.body.token}`)
165
+ .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
166
+ .expect(HTTP_STATUS.OK);
262
167
  });
263
168
  });
264
169
  });
@@ -1,78 +0,0 @@
1
- import supertest from 'supertest';
2
-
3
- import { API_ERROR, HEADERS, HEADER_TYPE, HTTP_STATUS, TOKEN_BEARER } from '@verdaccio/core';
4
- import { buildToken } from '@verdaccio/utils';
5
-
6
- import { createUser, getPackage, initializeServer } from './_helper';
7
-
8
- const FORBIDDEN_VUE = 'authorization required to access package vue';
9
-
10
- describe('token', () => {
11
- describe('basics', () => {
12
- const FAKE_TOKEN: string = buildToken(TOKEN_BEARER, 'fake');
13
- test.each([['user.yaml'], ['user.jwt.yaml']])('should test add a new user', async (conf) => {
14
- const app = await initializeServer(conf);
15
- const credentials = { name: 'JotaJWT', password: 'secretPass' };
16
- const response = await createUser(app, credentials.name, credentials.password);
17
- expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
18
-
19
- const vueResponse = await getPackage(app, response.body.token, 'vue');
20
- expect(vueResponse.body).toBeDefined();
21
- expect(vueResponse.body.name).toMatch('vue');
22
-
23
- const vueFailResp = await getPackage(app, FAKE_TOKEN, 'vue', HTTP_STATUS.UNAUTHORIZED);
24
- expect(vueFailResp.body.error).toMatch(FORBIDDEN_VUE);
25
- });
26
-
27
- test.each([['user.yaml'], ['user.jwt.yaml']])('should test add a new user', async (conf) => {
28
- const app = await initializeServer(conf);
29
- const credentials = { name: 'JotaJWT', password: 'secretPass' };
30
- const response = await createUser(app, credentials.name, credentials.password);
31
- expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
32
- const response2 = await supertest(app)
33
- .put(`/-/user/org.couchdb.user:${credentials.name}`)
34
- .send({
35
- name: credentials.name,
36
- password: credentials.password,
37
- })
38
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
39
- .expect(HTTP_STATUS.CONFLICT);
40
- expect(response2.body.error).toBe(API_ERROR.USERNAME_ALREADY_REGISTERED);
41
- });
42
-
43
- test.each([['user.yaml'], ['user.jwt.yaml']])(
44
- 'should fails on login if user credentials are invalid even if jwt',
45
- async (conf) => {
46
- const app = await initializeServer(conf);
47
- const credentials = { name: 'newFailsUser', password: 'secretPass' };
48
- const response = await createUser(app, credentials.name, credentials.password);
49
- expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
50
- const response2 = await supertest(app)
51
- .put(`/-/user/org.couchdb.user:${credentials.name}`)
52
- .send({
53
- name: credentials.name,
54
- password: 'BAD_PASSWORD',
55
- })
56
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
57
- .expect(HTTP_STATUS.UNAUTHORIZED);
58
- expect(response2.body.error).toBe(API_ERROR.UNAUTHORIZED_ACCESS);
59
- }
60
- );
61
-
62
- test.each([['user.yaml'], ['user.jwt.yaml']])(
63
- 'should verify if user is logged',
64
- async (conf) => {
65
- const app = await initializeServer(conf);
66
- const credentials = { name: 'jota', password: 'secretPass' };
67
- const response = await createUser(app, credentials.name, credentials.password);
68
- expect(response.body.ok).toMatch(`user '${credentials.name}' created`);
69
- const response2 = await supertest(app)
70
- .get(`/-/user/org.couchdb.user:${credentials.name}`)
71
- .set(HEADERS.AUTHORIZATION, buildToken(TOKEN_BEARER, response.body.token))
72
- .expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_CHARSET)
73
- .expect(HTTP_STATUS.OK);
74
- expect(response2.body.ok).toBe(`you are authenticated as '${credentials.name}'`);
75
- }
76
- );
77
- });
78
- });