@verdaccio/web 9.0.0-next-9.4 → 9.0.0-next-9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,16 +29,16 @@ If you want to report a security vulnerability, please follow the steps which we
29
29
 
30
30
  Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/verdaccio/contribute)]
31
31
 
32
- [![sponsor](https://opencollective.com/verdaccio/sponsor/0/avatar.svg)](https://opencollective.com/verdaccio/sponsor/0/website)
33
- [![sponsor](https://opencollective.com/verdaccio/sponsor/1/avatar.svg)](https://opencollective.com/verdaccio/sponsor/1/website)
34
- [![sponsor](https://opencollective.com/verdaccio/sponsor/2/avatar.svg)](https://opencollective.com/verdaccio/sponsor/2/website)
35
- [![sponsor](https://opencollective.com/verdaccio/sponsor/3/avatar.svg)](https://opencollective.com/verdaccio/sponsor/3/website)
36
- [![sponsor](https://opencollective.com/verdaccio/sponsor/4/avatar.svg)](https://opencollective.com/verdaccio/sponsor/4/website)
37
- [![sponsor](https://opencollective.com/verdaccio/sponsor/5/avatar.svg)](https://opencollective.com/verdaccio/sponsor/5/website)
38
- [![sponsor](https://opencollective.com/verdaccio/sponsor/6/avatar.svg)](https://opencollective.com/verdaccio/sponsor/6/website)
39
- [![sponsor](https://opencollective.com/verdaccio/sponsor/7/avatar.svg)](https://opencollective.com/verdaccio/sponsor/7/website)
40
- [![sponsor](https://opencollective.com/verdaccio/sponsor/8/avatar.svg)](https://opencollective.com/verdaccio/sponsor/8/website)
41
- [![sponsor](https://opencollective.com/verdaccio/sponsor/9/avatar.svg)](https://opencollective.com/verdaccio/sponsor/9/website)
32
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/0/avatar.png)](https://opencollective.com/verdaccio/sponsor/0/website)
33
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/1/avatar.png)](https://opencollective.com/verdaccio/sponsor/1/website)
34
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/2/avatar.png)](https://opencollective.com/verdaccio/sponsor/2/website)
35
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/3/avatar.png)](https://opencollective.com/verdaccio/sponsor/3/website)
36
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/4/avatar.png)](https://opencollective.com/verdaccio/sponsor/4/website)
37
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/5/avatar.png)](https://opencollective.com/verdaccio/sponsor/5/website)
38
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/6/avatar.png)](https://opencollective.com/verdaccio/sponsor/6/website)
39
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/7/avatar.png)](https://opencollective.com/verdaccio/sponsor/7/website)
40
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/8/avatar.png)](https://opencollective.com/verdaccio/sponsor/8/website)
41
+ [![sponsor](https://opencollective.com/verdaccio/sponsor/9/avatar.png)](https://opencollective.com/verdaccio/sponsor/9/website)
42
42
 
43
43
  ## Open Collective Backers
44
44
 
@@ -11,6 +11,9 @@ debug = require_runtime.__toESM(debug);
11
11
  let _verdaccio_config = require("@verdaccio/config");
12
12
  let _verdaccio_tarball = require("@verdaccio/tarball");
13
13
  //#region src/api/package.ts
14
+ var getField = (field = "name") => {
15
+ return field === "name" || field === "time" ? field : "name";
16
+ };
14
17
  var getOrder = (order = "asc") => {
15
18
  return order === "asc";
16
19
  };
@@ -62,9 +65,12 @@ function addPackageWebApi(storage, auth, config) {
62
65
  debug$1("hit package web api %o");
63
66
  try {
64
67
  const localPackages = await storage.getLocalDatabase();
68
+ const field = getField(config?.web?.sort_field);
65
69
  const order = getOrder(config?.web?.sort_packages);
66
- debug$1("order %o", order);
67
- next(require_web_utils.sortByName(await processPackages(localPackages, req), order));
70
+ debug$1("order by %o %o", field, order);
71
+ const pkgs = await processPackages(localPackages, req);
72
+ if (field === "name") next(require_web_utils.sortByName(pkgs, order));
73
+ else next(require_web_utils.sortByTime(pkgs, order));
68
74
  } catch (error) {
69
75
  next(error);
70
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":[],"sources":["../../src/api/package.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport type { Auth } from '@verdaccio/auth';\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport { logger } from '@verdaccio/logger';\nimport {\n $NextFunctionVer,\n $RequestExtend,\n $ResponseExtend,\n WebUrls,\n getRequestOptions,\n} from '@verdaccio/middleware';\nimport type { Storage } from '@verdaccio/store';\nimport { getLocalRegistryTarballUri } from '@verdaccio/tarball';\nimport type { Config, RemoteUser, Version } from '@verdaccio/types';\n\nimport { formatAuthor, generateGravatarUrl } from '../author-utils';\nimport { hasLogin, sortByName } from '../web-utils';\n\nexport { $RequestExtend, $ResponseExtend, $NextFunctionVer }; // Was required by other packages\n\nconst getOrder = (order = 'asc') => {\n return order === 'asc';\n};\n\nconst debug = buildDebug('verdaccio:web:api:package');\n\nfunction addPackageWebApi(storage: Storage, auth: Auth, config: Config): Router {\n const isLoginEnabled = hasLogin(config);\n debug('is login enabled: %o', isLoginEnabled);\n const pkgRouter = Router(); /* eslint new-cap: 0 */\n const anonymousRemoteUser: RemoteUser = createAnonymousRemoteUser();\n\n debug('initialized package web api');\n const checkAllow = (name: string, remoteUser: RemoteUser): Promise<boolean> =>\n new Promise((resolve, reject): void => {\n const remoteUserAccess = !isLoginEnabled ? anonymousRemoteUser : remoteUser;\n try {\n auth.allow_access({ packageName: name }, remoteUserAccess, (err, allowed): void => {\n if (err) {\n resolve(false);\n }\n return resolve(allowed as boolean);\n });\n } catch (err: any) {\n reject(err);\n }\n });\n\n async function processPackages(packages: Version[] = [], req): Promise<Version[]> {\n const permissions: Version[] = [];\n const packagesToProcess = packages.slice();\n debug('process packages %o', packagesToProcess);\n const requestOptions = getRequestOptions(req);\n for (const pkg of packagesToProcess) {\n const pkgCopy = { ...pkg };\n pkgCopy.author = formatAuthor(pkg.author);\n try {\n if (await checkAllow(pkg.name, req.remote_user)) {\n if (config.web) {\n // @ts-ignore\n pkgCopy.author.avatar = generateGravatarUrl(pkgCopy.author.email, config.web.gravatar);\n }\n // convert any remote dist to a local reference\n // eg: if the dist points to npmjs, switch to localhost:4873/prefix/etc.tar.gz\n if (!_.isNil(pkgCopy.dist) && !_.isNull(pkgCopy.dist.tarball)) {\n pkgCopy.dist.tarball = getLocalRegistryTarballUri(\n pkgCopy.dist.tarball,\n pkg.name,\n requestOptions,\n config?.url_prefix\n );\n }\n permissions.push(pkgCopy);\n }\n } catch (err: any) {\n debug('process packages error %o', err);\n logger.error(\n { name: pkg.name, error: err },\n 'permission process for @{name} has failed: @{error}'\n );\n throw err;\n }\n }\n\n debug('allowed %o packages', permissions.length);\n return permissions;\n }\n\n // Get list of all visible package\n pkgRouter.get(\n WebUrls.packages_all,\n async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n debug('hit package web api %o');\n\n try {\n const localPackages: Version[] = await storage.getLocalDatabase();\n\n const order = getOrder(config?.web?.sort_packages);\n debug('order %o', order);\n const pkgs = await processPackages(localPackages, req);\n next(sortByName(pkgs, order));\n } catch (error: any) {\n next(error);\n }\n }\n );\n\n return pkgRouter;\n}\n\nexport default addPackageWebApi;\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAM,YAAY,QAAQ,UAAU;AAClC,QAAO,UAAU;;AAGnB,IAAM,WAAA,GAAA,MAAA,SAAmB,4BAA4B;AAErD,SAAS,iBAAiB,SAAkB,MAAY,QAAwB;CAC9E,MAAM,iBAAiB,kBAAA,SAAS,OAAO;AACvC,SAAM,wBAAwB,eAAe;CAC7C,MAAM,aAAA,GAAA,QAAA,SAAoB;CAC1B,MAAM,uBAAA,GAAA,kBAAA,4BAA6D;AAEnE,SAAM,8BAA8B;CACpC,MAAM,cAAc,MAAc,eAChC,IAAI,SAAS,SAAS,WAAiB;EACrC,MAAM,mBAAmB,CAAC,iBAAiB,sBAAsB;AACjE,MAAI;AACF,QAAK,aAAa,EAAE,aAAa,MAAM,EAAE,mBAAmB,KAAK,YAAkB;AACjF,QAAI,IACF,SAAQ,MAAM;AAEhB,WAAO,QAAQ,QAAmB;KAClC;WACK,KAAU;AACjB,UAAO,IAAI;;GAEb;CAEJ,eAAe,gBAAgB,WAAsB,EAAE,EAAE,KAAyB;EAChF,MAAM,cAAyB,EAAE;EACjC,MAAM,oBAAoB,SAAS,OAAO;AAC1C,UAAM,uBAAuB,kBAAkB;EAC/C,MAAM,kBAAA,GAAA,sBAAA,mBAAmC,IAAI;AAC7C,OAAK,MAAM,OAAO,mBAAmB;GACnC,MAAM,UAAU,EAAE,GAAG,KAAK;AAC1B,WAAQ,SAAS,qBAAA,aAAa,IAAI,OAAO;AACzC,OAAI;AACF,QAAI,MAAM,WAAW,IAAI,MAAM,IAAI,YAAY,EAAE;AAC/C,SAAI,OAAO,IAET,SAAQ,OAAO,SAAS,qBAAA,oBAAoB,QAAQ,OAAO,OAAO,OAAO,IAAI,SAAS;AAIxF,SAAI,CAAC,OAAA,QAAE,MAAM,QAAQ,KAAK,IAAI,CAAC,OAAA,QAAE,OAAO,QAAQ,KAAK,QAAQ,CAC3D,SAAQ,KAAK,WAAA,GAAA,mBAAA,4BACX,QAAQ,KAAK,SACb,IAAI,MACJ,gBACA,QAAQ,WACT;AAEH,iBAAY,KAAK,QAAQ;;YAEpB,KAAU;AACjB,YAAM,6BAA6B,IAAI;AACvC,sBAAA,OAAO,MACL;KAAE,MAAM,IAAI;KAAM,OAAO;KAAK,EAC9B,sDACD;AACD,UAAM;;;AAIV,UAAM,uBAAuB,YAAY,OAAO;AAChD,SAAO;;AAIT,WAAU,IACR,sBAAA,QAAQ,cACR,eACE,KACA,KACA,MACe;AACf,UAAM,yBAAyB;AAE/B,MAAI;GACF,MAAM,gBAA2B,MAAM,QAAQ,kBAAkB;GAEjE,MAAM,QAAQ,SAAS,QAAQ,KAAK,cAAc;AAClD,WAAM,YAAY,MAAM;AAExB,QAAK,kBAAA,WADQ,MAAM,gBAAgB,eAAe,IAAI,EAChC,MAAM,CAAC;WACtB,OAAY;AACnB,QAAK,MAAM;;GAGhB;AAED,QAAO"}
1
+ {"version":3,"file":"package.js","names":[],"sources":["../../src/api/package.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport type { Auth } from '@verdaccio/auth';\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport { logger } from '@verdaccio/logger';\nimport {\n $NextFunctionVer,\n $RequestExtend,\n $ResponseExtend,\n WebUrls,\n getRequestOptions,\n} from '@verdaccio/middleware';\nimport type { Storage } from '@verdaccio/store';\nimport { getLocalRegistryTarballUri } from '@verdaccio/tarball';\nimport type { Config, RemoteUser, Version } from '@verdaccio/types';\n\nimport { formatAuthor, generateGravatarUrl } from '../author-utils';\nimport { hasLogin, sortByName, sortByTime } from '../web-utils';\n\nexport { $RequestExtend, $ResponseExtend, $NextFunctionVer }; // Was required by other packages\n\nconst getField = (field = 'name') => {\n return field === 'name' || field === 'time' ? field : 'name';\n};\n\nconst getOrder = (order = 'asc') => {\n return order === 'asc';\n};\n\nconst debug = buildDebug('verdaccio:web:api:package');\n\nfunction addPackageWebApi(storage: Storage, auth: Auth, config: Config): Router {\n const isLoginEnabled = hasLogin(config);\n debug('is login enabled: %o', isLoginEnabled);\n const pkgRouter = Router(); /* eslint new-cap: 0 */\n const anonymousRemoteUser: RemoteUser = createAnonymousRemoteUser();\n\n debug('initialized package web api');\n const checkAllow = (name: string, remoteUser: RemoteUser): Promise<boolean> =>\n new Promise((resolve, reject): void => {\n const remoteUserAccess = !isLoginEnabled ? anonymousRemoteUser : remoteUser;\n try {\n auth.allow_access({ packageName: name }, remoteUserAccess, (err, allowed): void => {\n if (err) {\n resolve(false);\n }\n return resolve(allowed as boolean);\n });\n } catch (err: any) {\n reject(err);\n }\n });\n\n async function processPackages(packages: Version[] = [], req): Promise<Version[]> {\n const permissions: Version[] = [];\n const packagesToProcess = packages.slice();\n debug('process packages %o', packagesToProcess);\n const requestOptions = getRequestOptions(req);\n for (const pkg of packagesToProcess) {\n const pkgCopy = { ...pkg };\n pkgCopy.author = formatAuthor(pkg.author);\n try {\n if (await checkAllow(pkg.name, req.remote_user)) {\n if (config.web) {\n // @ts-ignore\n pkgCopy.author.avatar = generateGravatarUrl(pkgCopy.author.email, config.web.gravatar);\n }\n // convert any remote dist to a local reference\n // eg: if the dist points to npmjs, switch to localhost:4873/prefix/etc.tar.gz\n if (!_.isNil(pkgCopy.dist) && !_.isNull(pkgCopy.dist.tarball)) {\n pkgCopy.dist.tarball = getLocalRegistryTarballUri(\n pkgCopy.dist.tarball,\n pkg.name,\n requestOptions,\n config?.url_prefix\n );\n }\n permissions.push(pkgCopy);\n }\n } catch (err: any) {\n debug('process packages error %o', err);\n logger.error(\n { name: pkg.name, error: err },\n 'permission process for @{name} has failed: @{error}'\n );\n throw err;\n }\n }\n\n debug('allowed %o packages', permissions.length);\n return permissions;\n }\n\n // Get list of all visible package\n pkgRouter.get(\n WebUrls.packages_all,\n async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n debug('hit package web api %o');\n\n try {\n const localPackages: Version[] = await storage.getLocalDatabase();\n\n const field = getField(config?.web?.sort_field);\n const order = getOrder(config?.web?.sort_packages);\n debug('order by %o %o', field, order);\n const pkgs = await processPackages(localPackages, req);\n if (field === 'name') next(sortByName(pkgs, order));\n else next(sortByTime(pkgs, order));\n } catch (error: any) {\n next(error);\n }\n }\n );\n\n return pkgRouter;\n}\n\nexport default addPackageWebApi;\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAM,YAAY,QAAQ,WAAW;AACnC,QAAO,UAAU,UAAU,UAAU,SAAS,QAAQ;;AAGxD,IAAM,YAAY,QAAQ,UAAU;AAClC,QAAO,UAAU;;AAGnB,IAAM,WAAA,GAAA,MAAA,SAAmB,4BAA4B;AAErD,SAAS,iBAAiB,SAAkB,MAAY,QAAwB;CAC9E,MAAM,iBAAiB,kBAAA,SAAS,OAAO;AACvC,SAAM,wBAAwB,eAAe;CAC7C,MAAM,aAAA,GAAA,QAAA,SAAoB;CAC1B,MAAM,uBAAA,GAAA,kBAAA,4BAA6D;AAEnE,SAAM,8BAA8B;CACpC,MAAM,cAAc,MAAc,eAChC,IAAI,SAAS,SAAS,WAAiB;EACrC,MAAM,mBAAmB,CAAC,iBAAiB,sBAAsB;AACjE,MAAI;AACF,QAAK,aAAa,EAAE,aAAa,MAAM,EAAE,mBAAmB,KAAK,YAAkB;AACjF,QAAI,IACF,SAAQ,MAAM;AAEhB,WAAO,QAAQ,QAAmB;KAClC;WACK,KAAU;AACjB,UAAO,IAAI;;GAEb;CAEJ,eAAe,gBAAgB,WAAsB,EAAE,EAAE,KAAyB;EAChF,MAAM,cAAyB,EAAE;EACjC,MAAM,oBAAoB,SAAS,OAAO;AAC1C,UAAM,uBAAuB,kBAAkB;EAC/C,MAAM,kBAAA,GAAA,sBAAA,mBAAmC,IAAI;AAC7C,OAAK,MAAM,OAAO,mBAAmB;GACnC,MAAM,UAAU,EAAE,GAAG,KAAK;AAC1B,WAAQ,SAAS,qBAAA,aAAa,IAAI,OAAO;AACzC,OAAI;AACF,QAAI,MAAM,WAAW,IAAI,MAAM,IAAI,YAAY,EAAE;AAC/C,SAAI,OAAO,IAET,SAAQ,OAAO,SAAS,qBAAA,oBAAoB,QAAQ,OAAO,OAAO,OAAO,IAAI,SAAS;AAIxF,SAAI,CAAC,OAAA,QAAE,MAAM,QAAQ,KAAK,IAAI,CAAC,OAAA,QAAE,OAAO,QAAQ,KAAK,QAAQ,CAC3D,SAAQ,KAAK,WAAA,GAAA,mBAAA,4BACX,QAAQ,KAAK,SACb,IAAI,MACJ,gBACA,QAAQ,WACT;AAEH,iBAAY,KAAK,QAAQ;;YAEpB,KAAU;AACjB,YAAM,6BAA6B,IAAI;AACvC,sBAAA,OAAO,MACL;KAAE,MAAM,IAAI;KAAM,OAAO;KAAK,EAC9B,sDACD;AACD,UAAM;;;AAIV,UAAM,uBAAuB,YAAY,OAAO;AAChD,SAAO;;AAIT,WAAU,IACR,sBAAA,QAAQ,cACR,eACE,KACA,KACA,MACe;AACf,UAAM,yBAAyB;AAE/B,MAAI;GACF,MAAM,gBAA2B,MAAM,QAAQ,kBAAkB;GAEjE,MAAM,QAAQ,SAAS,QAAQ,KAAK,WAAW;GAC/C,MAAM,QAAQ,SAAS,QAAQ,KAAK,cAAc;AAClD,WAAM,kBAAkB,OAAO,MAAM;GACrC,MAAM,OAAO,MAAM,gBAAgB,eAAe,IAAI;AACtD,OAAI,UAAU,OAAQ,MAAK,kBAAA,WAAW,MAAM,MAAM,CAAC;OAC9C,MAAK,kBAAA,WAAW,MAAM,MAAM,CAAC;WAC3B,OAAY;AACnB,QAAK,MAAM;;GAGhB;AAED,QAAO"}
@@ -1,4 +1,4 @@
1
- import { hasLogin, sortByName } from "../web-utils.mjs";
1
+ import { hasLogin, sortByName, sortByTime } from "../web-utils.mjs";
2
2
  import { formatAuthor, generateGravatarUrl } from "../author-utils.mjs";
3
3
  import { Router } from "express";
4
4
  import _ from "lodash";
@@ -8,6 +8,9 @@ import buildDebug from "debug";
8
8
  import { createAnonymousRemoteUser } from "@verdaccio/config";
9
9
  import { getLocalRegistryTarballUri } from "@verdaccio/tarball";
10
10
  //#region src/api/package.ts
11
+ var getField = (field = "name") => {
12
+ return field === "name" || field === "time" ? field : "name";
13
+ };
11
14
  var getOrder = (order = "asc") => {
12
15
  return order === "asc";
13
16
  };
@@ -59,9 +62,12 @@ function addPackageWebApi(storage, auth, config) {
59
62
  debug("hit package web api %o");
60
63
  try {
61
64
  const localPackages = await storage.getLocalDatabase();
65
+ const field = getField(config?.web?.sort_field);
62
66
  const order = getOrder(config?.web?.sort_packages);
63
- debug("order %o", order);
64
- next(sortByName(await processPackages(localPackages, req), order));
67
+ debug("order by %o %o", field, order);
68
+ const pkgs = await processPackages(localPackages, req);
69
+ if (field === "name") next(sortByName(pkgs, order));
70
+ else next(sortByTime(pkgs, order));
65
71
  } catch (error) {
66
72
  next(error);
67
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"package.mjs","names":[],"sources":["../../src/api/package.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport type { Auth } from '@verdaccio/auth';\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport { logger } from '@verdaccio/logger';\nimport {\n $NextFunctionVer,\n $RequestExtend,\n $ResponseExtend,\n WebUrls,\n getRequestOptions,\n} from '@verdaccio/middleware';\nimport type { Storage } from '@verdaccio/store';\nimport { getLocalRegistryTarballUri } from '@verdaccio/tarball';\nimport type { Config, RemoteUser, Version } from '@verdaccio/types';\n\nimport { formatAuthor, generateGravatarUrl } from '../author-utils';\nimport { hasLogin, sortByName } from '../web-utils';\n\nexport { $RequestExtend, $ResponseExtend, $NextFunctionVer }; // Was required by other packages\n\nconst getOrder = (order = 'asc') => {\n return order === 'asc';\n};\n\nconst debug = buildDebug('verdaccio:web:api:package');\n\nfunction addPackageWebApi(storage: Storage, auth: Auth, config: Config): Router {\n const isLoginEnabled = hasLogin(config);\n debug('is login enabled: %o', isLoginEnabled);\n const pkgRouter = Router(); /* eslint new-cap: 0 */\n const anonymousRemoteUser: RemoteUser = createAnonymousRemoteUser();\n\n debug('initialized package web api');\n const checkAllow = (name: string, remoteUser: RemoteUser): Promise<boolean> =>\n new Promise((resolve, reject): void => {\n const remoteUserAccess = !isLoginEnabled ? anonymousRemoteUser : remoteUser;\n try {\n auth.allow_access({ packageName: name }, remoteUserAccess, (err, allowed): void => {\n if (err) {\n resolve(false);\n }\n return resolve(allowed as boolean);\n });\n } catch (err: any) {\n reject(err);\n }\n });\n\n async function processPackages(packages: Version[] = [], req): Promise<Version[]> {\n const permissions: Version[] = [];\n const packagesToProcess = packages.slice();\n debug('process packages %o', packagesToProcess);\n const requestOptions = getRequestOptions(req);\n for (const pkg of packagesToProcess) {\n const pkgCopy = { ...pkg };\n pkgCopy.author = formatAuthor(pkg.author);\n try {\n if (await checkAllow(pkg.name, req.remote_user)) {\n if (config.web) {\n // @ts-ignore\n pkgCopy.author.avatar = generateGravatarUrl(pkgCopy.author.email, config.web.gravatar);\n }\n // convert any remote dist to a local reference\n // eg: if the dist points to npmjs, switch to localhost:4873/prefix/etc.tar.gz\n if (!_.isNil(pkgCopy.dist) && !_.isNull(pkgCopy.dist.tarball)) {\n pkgCopy.dist.tarball = getLocalRegistryTarballUri(\n pkgCopy.dist.tarball,\n pkg.name,\n requestOptions,\n config?.url_prefix\n );\n }\n permissions.push(pkgCopy);\n }\n } catch (err: any) {\n debug('process packages error %o', err);\n logger.error(\n { name: pkg.name, error: err },\n 'permission process for @{name} has failed: @{error}'\n );\n throw err;\n }\n }\n\n debug('allowed %o packages', permissions.length);\n return permissions;\n }\n\n // Get list of all visible package\n pkgRouter.get(\n WebUrls.packages_all,\n async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n debug('hit package web api %o');\n\n try {\n const localPackages: Version[] = await storage.getLocalDatabase();\n\n const order = getOrder(config?.web?.sort_packages);\n debug('order %o', order);\n const pkgs = await processPackages(localPackages, req);\n next(sortByName(pkgs, order));\n } catch (error: any) {\n next(error);\n }\n }\n );\n\n return pkgRouter;\n}\n\nexport default addPackageWebApi;\n"],"mappings":";;;;;;;;;;AAuBA,IAAM,YAAY,QAAQ,UAAU;AAClC,QAAO,UAAU;;AAGnB,IAAM,QAAQ,WAAW,4BAA4B;AAErD,SAAS,iBAAiB,SAAkB,MAAY,QAAwB;CAC9E,MAAM,iBAAiB,SAAS,OAAO;AACvC,OAAM,wBAAwB,eAAe;CAC7C,MAAM,YAAY,QAAQ;CAC1B,MAAM,sBAAkC,2BAA2B;AAEnE,OAAM,8BAA8B;CACpC,MAAM,cAAc,MAAc,eAChC,IAAI,SAAS,SAAS,WAAiB;EACrC,MAAM,mBAAmB,CAAC,iBAAiB,sBAAsB;AACjE,MAAI;AACF,QAAK,aAAa,EAAE,aAAa,MAAM,EAAE,mBAAmB,KAAK,YAAkB;AACjF,QAAI,IACF,SAAQ,MAAM;AAEhB,WAAO,QAAQ,QAAmB;KAClC;WACK,KAAU;AACjB,UAAO,IAAI;;GAEb;CAEJ,eAAe,gBAAgB,WAAsB,EAAE,EAAE,KAAyB;EAChF,MAAM,cAAyB,EAAE;EACjC,MAAM,oBAAoB,SAAS,OAAO;AAC1C,QAAM,uBAAuB,kBAAkB;EAC/C,MAAM,iBAAiB,kBAAkB,IAAI;AAC7C,OAAK,MAAM,OAAO,mBAAmB;GACnC,MAAM,UAAU,EAAE,GAAG,KAAK;AAC1B,WAAQ,SAAS,aAAa,IAAI,OAAO;AACzC,OAAI;AACF,QAAI,MAAM,WAAW,IAAI,MAAM,IAAI,YAAY,EAAE;AAC/C,SAAI,OAAO,IAET,SAAQ,OAAO,SAAS,oBAAoB,QAAQ,OAAO,OAAO,OAAO,IAAI,SAAS;AAIxF,SAAI,CAAC,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAC3D,SAAQ,KAAK,UAAU,2BACrB,QAAQ,KAAK,SACb,IAAI,MACJ,gBACA,QAAQ,WACT;AAEH,iBAAY,KAAK,QAAQ;;YAEpB,KAAU;AACjB,UAAM,6BAA6B,IAAI;AACvC,WAAO,MACL;KAAE,MAAM,IAAI;KAAM,OAAO;KAAK,EAC9B,sDACD;AACD,UAAM;;;AAIV,QAAM,uBAAuB,YAAY,OAAO;AAChD,SAAO;;AAIT,WAAU,IACR,QAAQ,cACR,eACE,KACA,KACA,MACe;AACf,QAAM,yBAAyB;AAE/B,MAAI;GACF,MAAM,gBAA2B,MAAM,QAAQ,kBAAkB;GAEjE,MAAM,QAAQ,SAAS,QAAQ,KAAK,cAAc;AAClD,SAAM,YAAY,MAAM;AAExB,QAAK,WADQ,MAAM,gBAAgB,eAAe,IAAI,EAChC,MAAM,CAAC;WACtB,OAAY;AACnB,QAAK,MAAM;;GAGhB;AAED,QAAO"}
1
+ {"version":3,"file":"package.mjs","names":[],"sources":["../../src/api/package.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport type { Auth } from '@verdaccio/auth';\nimport { createAnonymousRemoteUser } from '@verdaccio/config';\nimport { logger } from '@verdaccio/logger';\nimport {\n $NextFunctionVer,\n $RequestExtend,\n $ResponseExtend,\n WebUrls,\n getRequestOptions,\n} from '@verdaccio/middleware';\nimport type { Storage } from '@verdaccio/store';\nimport { getLocalRegistryTarballUri } from '@verdaccio/tarball';\nimport type { Config, RemoteUser, Version } from '@verdaccio/types';\n\nimport { formatAuthor, generateGravatarUrl } from '../author-utils';\nimport { hasLogin, sortByName, sortByTime } from '../web-utils';\n\nexport { $RequestExtend, $ResponseExtend, $NextFunctionVer }; // Was required by other packages\n\nconst getField = (field = 'name') => {\n return field === 'name' || field === 'time' ? field : 'name';\n};\n\nconst getOrder = (order = 'asc') => {\n return order === 'asc';\n};\n\nconst debug = buildDebug('verdaccio:web:api:package');\n\nfunction addPackageWebApi(storage: Storage, auth: Auth, config: Config): Router {\n const isLoginEnabled = hasLogin(config);\n debug('is login enabled: %o', isLoginEnabled);\n const pkgRouter = Router(); /* eslint new-cap: 0 */\n const anonymousRemoteUser: RemoteUser = createAnonymousRemoteUser();\n\n debug('initialized package web api');\n const checkAllow = (name: string, remoteUser: RemoteUser): Promise<boolean> =>\n new Promise((resolve, reject): void => {\n const remoteUserAccess = !isLoginEnabled ? anonymousRemoteUser : remoteUser;\n try {\n auth.allow_access({ packageName: name }, remoteUserAccess, (err, allowed): void => {\n if (err) {\n resolve(false);\n }\n return resolve(allowed as boolean);\n });\n } catch (err: any) {\n reject(err);\n }\n });\n\n async function processPackages(packages: Version[] = [], req): Promise<Version[]> {\n const permissions: Version[] = [];\n const packagesToProcess = packages.slice();\n debug('process packages %o', packagesToProcess);\n const requestOptions = getRequestOptions(req);\n for (const pkg of packagesToProcess) {\n const pkgCopy = { ...pkg };\n pkgCopy.author = formatAuthor(pkg.author);\n try {\n if (await checkAllow(pkg.name, req.remote_user)) {\n if (config.web) {\n // @ts-ignore\n pkgCopy.author.avatar = generateGravatarUrl(pkgCopy.author.email, config.web.gravatar);\n }\n // convert any remote dist to a local reference\n // eg: if the dist points to npmjs, switch to localhost:4873/prefix/etc.tar.gz\n if (!_.isNil(pkgCopy.dist) && !_.isNull(pkgCopy.dist.tarball)) {\n pkgCopy.dist.tarball = getLocalRegistryTarballUri(\n pkgCopy.dist.tarball,\n pkg.name,\n requestOptions,\n config?.url_prefix\n );\n }\n permissions.push(pkgCopy);\n }\n } catch (err: any) {\n debug('process packages error %o', err);\n logger.error(\n { name: pkg.name, error: err },\n 'permission process for @{name} has failed: @{error}'\n );\n throw err;\n }\n }\n\n debug('allowed %o packages', permissions.length);\n return permissions;\n }\n\n // Get list of all visible package\n pkgRouter.get(\n WebUrls.packages_all,\n async function (\n req: $RequestExtend,\n res: $ResponseExtend,\n next: $NextFunctionVer\n ): Promise<void> {\n debug('hit package web api %o');\n\n try {\n const localPackages: Version[] = await storage.getLocalDatabase();\n\n const field = getField(config?.web?.sort_field);\n const order = getOrder(config?.web?.sort_packages);\n debug('order by %o %o', field, order);\n const pkgs = await processPackages(localPackages, req);\n if (field === 'name') next(sortByName(pkgs, order));\n else next(sortByTime(pkgs, order));\n } catch (error: any) {\n next(error);\n }\n }\n );\n\n return pkgRouter;\n}\n\nexport default addPackageWebApi;\n"],"mappings":";;;;;;;;;;AAuBA,IAAM,YAAY,QAAQ,WAAW;AACnC,QAAO,UAAU,UAAU,UAAU,SAAS,QAAQ;;AAGxD,IAAM,YAAY,QAAQ,UAAU;AAClC,QAAO,UAAU;;AAGnB,IAAM,QAAQ,WAAW,4BAA4B;AAErD,SAAS,iBAAiB,SAAkB,MAAY,QAAwB;CAC9E,MAAM,iBAAiB,SAAS,OAAO;AACvC,OAAM,wBAAwB,eAAe;CAC7C,MAAM,YAAY,QAAQ;CAC1B,MAAM,sBAAkC,2BAA2B;AAEnE,OAAM,8BAA8B;CACpC,MAAM,cAAc,MAAc,eAChC,IAAI,SAAS,SAAS,WAAiB;EACrC,MAAM,mBAAmB,CAAC,iBAAiB,sBAAsB;AACjE,MAAI;AACF,QAAK,aAAa,EAAE,aAAa,MAAM,EAAE,mBAAmB,KAAK,YAAkB;AACjF,QAAI,IACF,SAAQ,MAAM;AAEhB,WAAO,QAAQ,QAAmB;KAClC;WACK,KAAU;AACjB,UAAO,IAAI;;GAEb;CAEJ,eAAe,gBAAgB,WAAsB,EAAE,EAAE,KAAyB;EAChF,MAAM,cAAyB,EAAE;EACjC,MAAM,oBAAoB,SAAS,OAAO;AAC1C,QAAM,uBAAuB,kBAAkB;EAC/C,MAAM,iBAAiB,kBAAkB,IAAI;AAC7C,OAAK,MAAM,OAAO,mBAAmB;GACnC,MAAM,UAAU,EAAE,GAAG,KAAK;AAC1B,WAAQ,SAAS,aAAa,IAAI,OAAO;AACzC,OAAI;AACF,QAAI,MAAM,WAAW,IAAI,MAAM,IAAI,YAAY,EAAE;AAC/C,SAAI,OAAO,IAET,SAAQ,OAAO,SAAS,oBAAoB,QAAQ,OAAO,OAAO,OAAO,IAAI,SAAS;AAIxF,SAAI,CAAC,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAC3D,SAAQ,KAAK,UAAU,2BACrB,QAAQ,KAAK,SACb,IAAI,MACJ,gBACA,QAAQ,WACT;AAEH,iBAAY,KAAK,QAAQ;;YAEpB,KAAU;AACjB,UAAM,6BAA6B,IAAI;AACvC,WAAO,MACL;KAAE,MAAM,IAAI;KAAM,OAAO;KAAK,EAC9B,sDACD;AACD,UAAM;;;AAIV,QAAM,uBAAuB,YAAY,OAAO;AAChD,SAAO;;AAIT,WAAU,IACR,QAAQ,cACR,eACE,KACA,KACA,MACe;AACf,QAAM,yBAAyB;AAE/B,MAAI;GACF,MAAM,gBAA2B,MAAM,QAAQ,kBAAkB;GAEjE,MAAM,QAAQ,SAAS,QAAQ,KAAK,WAAW;GAC/C,MAAM,QAAQ,SAAS,QAAQ,KAAK,cAAc;AAClD,SAAM,kBAAkB,OAAO,MAAM;GACrC,MAAM,OAAO,MAAM,gBAAgB,eAAe,IAAI;AACtD,OAAI,UAAU,OAAQ,MAAK,WAAW,MAAM,MAAM,CAAC;OAC9C,MAAK,WAAW,MAAM,MAAM,CAAC;WAC3B,OAAY;AACnB,QAAK,MAAM;;GAGhB;AAED,QAAO"}
package/build/api/user.js CHANGED
@@ -23,7 +23,7 @@ function addUserAuthApi(auth, config, storage) {
23
23
  } else {
24
24
  req.remote_user = user;
25
25
  const jWTSignOptions = config.security.web.sign;
26
- res.set(_verdaccio_core.HEADERS.CACHE_CONTROL, "no-cache, no-store");
26
+ res.set(_verdaccio_core.HEADERS.CACHE_CONTROL, _verdaccio_core.HEADERS.NO_CACHE);
27
27
  next({
28
28
  token: await auth.jwtEncrypt(user, jWTSignOptions),
29
29
  username: req.remote_user.name
@@ -1 +1 @@
1
- {"version":3,"file":"user.js","names":[],"sources":["../../src/api/user.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Request, Response } from 'express';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport { type Auth, getApiToken } from '@verdaccio/auth';\nimport type { VerdaccioError } from '@verdaccio/core';\nimport {\n API_ERROR,\n APP_ERROR,\n HEADERS,\n HTTP_STATUS,\n cryptoUtils,\n errorUtils,\n validationUtils,\n} from '@verdaccio/core';\nimport { WebUrls, rateLimit } from '@verdaccio/middleware';\nimport type { Config, JWTSignOptions, RemoteUser } from '@verdaccio/types';\n\nimport type { $NextFunctionVer } from './package';\n\nconst debug = buildDebug('verdaccio:web:api:user');\n\nconst WEB_LOGIN_SESSION_ID = 'web-login-sessionId';\n\nfunction addUserAuthApi(auth: Auth, config: Config, storage: Storage): Router {\n const route = Router(); /* eslint new-cap: 0 */\n route.post(\n WebUrls.user_login,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { username, password } = req.body;\n debug('authenticate %o', username);\n auth.authenticate(\n username,\n password,\n async (err: VerdaccioError | null, user?: RemoteUser): Promise<void> => {\n if (err) {\n const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR;\n debug('error authenticate %o', errorCode);\n next(errorUtils.getCode(errorCode, err.message));\n } else {\n req.remote_user = user as RemoteUser;\n const jWTSignOptions: JWTSignOptions = config.security.web.sign;\n res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');\n next({\n token: await auth.jwtEncrypt(user as RemoteUser, jWTSignOptions),\n username: req.remote_user.name,\n });\n }\n }\n );\n }\n );\n\n if (config?.flags?.createUser === true) {\n route.put(\n WebUrls.user_signup,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { name, password, email, sessionId } = req.body;\n debug('login or adduser');\n\n // TOOD: reuse with login.ts file\n if (typeof sessionId !== 'string' || sessionId.length !== 36) {\n debug('sessionId is invalid length: %o', sessionId.length);\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.SESSION_ID_INVALID));\n }\n\n if (!name || !password || !email) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.BAD_DATA));\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 tokens = await storage.readTokens({ user: sessionId });\n debug('tokens found for sessionId %o: %o', sessionId, tokens.length);\n if (tokens && tokens.length === 1 && tokens[0].key === WEB_LOGIN_SESSION_ID) {\n if (tokens[0].token.length === 0) {\n debug('waiting for authentication');\n // Poll again after short delay\n // TODO: make this configurable (default 5 seconds)\n res.status(HTTP_STATUS.ACCEPTED);\n res.set(HEADERS.RETRY_AFTER, '5');\n res.json({});\n return;\n }\n\n // session token can only be used once\n debug('deleting session token');\n await storage.deleteToken(sessionId, tokens[0].key);\n\n // Check if token has expired\n // TODO: make this configurable (default 2 minutes)\n const tokenCreatedDate = new Date(tokens[0].created);\n const minutesAgo = new Date(Date.now() - 2 * 60 * 1000);\n if (tokenCreatedDate < minutesAgo) {\n debug('session token expired');\n return next(errorUtils.getUnauthorized(API_ERROR.SESSION_TOKEN_EXPIRED));\n }\n\n debug('session token is valid, login successful');\n res.status(HTTP_STATUS.OK);\n res.json({ token: tokens[0].token });\n return;\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', cryptoUtils.mask(token as string, 4));\n return next({ token, username: name });\n }\n return next(errorUtils.getUnauthorized());\n });\n }\n );\n }\n\n if (config?.flags?.changePassword === true) {\n route.put(\n WebUrls.reset_password,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name)) {\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n // FUTURE: update to a more meaningful message\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n\n const { password } = req.body;\n const { name } = req.remote_user;\n\n if (\n validationUtils.validatePassword(\n password.new,\n config?.server?.passwordValidationRegex\n ) === false\n ) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, APP_ERROR.PASSWORD_VALIDATION));\n }\n\n auth.changePassword(name as string, password.old, password.new, (err, isUpdated): void => {\n if (_.isNil(err) && isUpdated) {\n next({\n ok: true,\n });\n } else {\n return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));\n }\n });\n }\n );\n }\n\n return route;\n}\n\nexport default addUserAuthApi;\n"],"mappings":"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"}
1
+ {"version":3,"file":"user.js","names":[],"sources":["../../src/api/user.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Request, Response } from 'express';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport { type Auth, getApiToken } from '@verdaccio/auth';\nimport type { VerdaccioError } from '@verdaccio/core';\nimport {\n API_ERROR,\n APP_ERROR,\n HEADERS,\n HTTP_STATUS,\n cryptoUtils,\n errorUtils,\n validationUtils,\n} from '@verdaccio/core';\nimport { WebUrls, rateLimit } from '@verdaccio/middleware';\nimport type { Config, JWTSignOptions, RemoteUser } from '@verdaccio/types';\n\nimport type { $NextFunctionVer } from './package';\n\nconst debug = buildDebug('verdaccio:web:api:user');\n\nconst WEB_LOGIN_SESSION_ID = 'web-login-sessionId';\n\nfunction addUserAuthApi(auth: Auth, config: Config, storage: Storage): Router {\n const route = Router(); /* eslint new-cap: 0 */\n route.post(\n WebUrls.user_login,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { username, password } = req.body;\n debug('authenticate %o', username);\n auth.authenticate(\n username,\n password,\n async (err: VerdaccioError | null, user?: RemoteUser): Promise<void> => {\n if (err) {\n const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR;\n debug('error authenticate %o', errorCode);\n next(errorUtils.getCode(errorCode, err.message));\n } else {\n req.remote_user = user as RemoteUser;\n const jWTSignOptions: JWTSignOptions = config.security.web.sign;\n res.set(HEADERS.CACHE_CONTROL, HEADERS.NO_CACHE);\n next({\n token: await auth.jwtEncrypt(user as RemoteUser, jWTSignOptions),\n username: req.remote_user.name,\n });\n }\n }\n );\n }\n );\n\n if (config?.flags?.createUser === true) {\n route.put(\n WebUrls.user_signup,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { name, password, email, sessionId } = req.body;\n debug('login or adduser');\n\n // TOOD: reuse with login.ts file\n if (typeof sessionId !== 'string' || sessionId.length !== 36) {\n debug('sessionId is invalid length: %o', sessionId.length);\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.SESSION_ID_INVALID));\n }\n\n if (!name || !password || !email) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.BAD_DATA));\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 tokens = await storage.readTokens({ user: sessionId });\n debug('tokens found for sessionId %o: %o', sessionId, tokens.length);\n if (tokens && tokens.length === 1 && tokens[0].key === WEB_LOGIN_SESSION_ID) {\n if (tokens[0].token.length === 0) {\n debug('waiting for authentication');\n // Poll again after short delay\n // TODO: make this configurable (default 5 seconds)\n res.status(HTTP_STATUS.ACCEPTED);\n res.set(HEADERS.RETRY_AFTER, '5');\n res.json({});\n return;\n }\n\n // session token can only be used once\n debug('deleting session token');\n await storage.deleteToken(sessionId, tokens[0].key);\n\n // Check if token has expired\n // TODO: make this configurable (default 2 minutes)\n const tokenCreatedDate = new Date(tokens[0].created);\n const minutesAgo = new Date(Date.now() - 2 * 60 * 1000);\n if (tokenCreatedDate < minutesAgo) {\n debug('session token expired');\n return next(errorUtils.getUnauthorized(API_ERROR.SESSION_TOKEN_EXPIRED));\n }\n\n debug('session token is valid, login successful');\n res.status(HTTP_STATUS.OK);\n res.json({ token: tokens[0].token });\n return;\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', cryptoUtils.mask(token as string, 4));\n return next({ token, username: name });\n }\n return next(errorUtils.getUnauthorized());\n });\n }\n );\n }\n\n if (config?.flags?.changePassword === true) {\n route.put(\n WebUrls.reset_password,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name)) {\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n // FUTURE: update to a more meaningful message\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n\n const { password } = req.body;\n const { name } = req.remote_user;\n\n if (\n validationUtils.validatePassword(\n password.new,\n config?.server?.passwordValidationRegex\n ) === false\n ) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, APP_ERROR.PASSWORD_VALIDATION));\n }\n\n auth.changePassword(name as string, password.old, password.new, (err, isUpdated): void => {\n if (_.isNil(err) && isUpdated) {\n next({\n ok: true,\n });\n } else {\n return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));\n }\n });\n }\n );\n }\n\n return route;\n}\n\nexport default addUserAuthApi;\n"],"mappings":"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"}
@@ -20,7 +20,7 @@ function addUserAuthApi(auth, config, storage) {
20
20
  } else {
21
21
  req.remote_user = user;
22
22
  const jWTSignOptions = config.security.web.sign;
23
- res.set(HEADERS.CACHE_CONTROL, "no-cache, no-store");
23
+ res.set(HEADERS.CACHE_CONTROL, HEADERS.NO_CACHE);
24
24
  next({
25
25
  token: await auth.jwtEncrypt(user, jWTSignOptions),
26
26
  username: req.remote_user.name
@@ -1 +1 @@
1
- {"version":3,"file":"user.mjs","names":[],"sources":["../../src/api/user.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Request, Response } from 'express';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport { type Auth, getApiToken } from '@verdaccio/auth';\nimport type { VerdaccioError } from '@verdaccio/core';\nimport {\n API_ERROR,\n APP_ERROR,\n HEADERS,\n HTTP_STATUS,\n cryptoUtils,\n errorUtils,\n validationUtils,\n} from '@verdaccio/core';\nimport { WebUrls, rateLimit } from '@verdaccio/middleware';\nimport type { Config, JWTSignOptions, RemoteUser } from '@verdaccio/types';\n\nimport type { $NextFunctionVer } from './package';\n\nconst debug = buildDebug('verdaccio:web:api:user');\n\nconst WEB_LOGIN_SESSION_ID = 'web-login-sessionId';\n\nfunction addUserAuthApi(auth: Auth, config: Config, storage: Storage): Router {\n const route = Router(); /* eslint new-cap: 0 */\n route.post(\n WebUrls.user_login,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { username, password } = req.body;\n debug('authenticate %o', username);\n auth.authenticate(\n username,\n password,\n async (err: VerdaccioError | null, user?: RemoteUser): Promise<void> => {\n if (err) {\n const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR;\n debug('error authenticate %o', errorCode);\n next(errorUtils.getCode(errorCode, err.message));\n } else {\n req.remote_user = user as RemoteUser;\n const jWTSignOptions: JWTSignOptions = config.security.web.sign;\n res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');\n next({\n token: await auth.jwtEncrypt(user as RemoteUser, jWTSignOptions),\n username: req.remote_user.name,\n });\n }\n }\n );\n }\n );\n\n if (config?.flags?.createUser === true) {\n route.put(\n WebUrls.user_signup,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { name, password, email, sessionId } = req.body;\n debug('login or adduser');\n\n // TOOD: reuse with login.ts file\n if (typeof sessionId !== 'string' || sessionId.length !== 36) {\n debug('sessionId is invalid length: %o', sessionId.length);\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.SESSION_ID_INVALID));\n }\n\n if (!name || !password || !email) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.BAD_DATA));\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 tokens = await storage.readTokens({ user: sessionId });\n debug('tokens found for sessionId %o: %o', sessionId, tokens.length);\n if (tokens && tokens.length === 1 && tokens[0].key === WEB_LOGIN_SESSION_ID) {\n if (tokens[0].token.length === 0) {\n debug('waiting for authentication');\n // Poll again after short delay\n // TODO: make this configurable (default 5 seconds)\n res.status(HTTP_STATUS.ACCEPTED);\n res.set(HEADERS.RETRY_AFTER, '5');\n res.json({});\n return;\n }\n\n // session token can only be used once\n debug('deleting session token');\n await storage.deleteToken(sessionId, tokens[0].key);\n\n // Check if token has expired\n // TODO: make this configurable (default 2 minutes)\n const tokenCreatedDate = new Date(tokens[0].created);\n const minutesAgo = new Date(Date.now() - 2 * 60 * 1000);\n if (tokenCreatedDate < minutesAgo) {\n debug('session token expired');\n return next(errorUtils.getUnauthorized(API_ERROR.SESSION_TOKEN_EXPIRED));\n }\n\n debug('session token is valid, login successful');\n res.status(HTTP_STATUS.OK);\n res.json({ token: tokens[0].token });\n return;\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', cryptoUtils.mask(token as string, 4));\n return next({ token, username: name });\n }\n return next(errorUtils.getUnauthorized());\n });\n }\n );\n }\n\n if (config?.flags?.changePassword === true) {\n route.put(\n WebUrls.reset_password,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name)) {\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n // FUTURE: update to a more meaningful message\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n\n const { password } = req.body;\n const { name } = req.remote_user;\n\n if (\n validationUtils.validatePassword(\n password.new,\n config?.server?.passwordValidationRegex\n ) === false\n ) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, APP_ERROR.PASSWORD_VALIDATION));\n }\n\n auth.changePassword(name as string, password.old, password.new, (err, isUpdated): void => {\n if (_.isNil(err) && isUpdated) {\n next({\n ok: true,\n });\n } else {\n return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));\n }\n });\n }\n );\n }\n\n return route;\n}\n\nexport default addUserAuthApi;\n"],"mappings":"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"}
1
+ {"version":3,"file":"user.mjs","names":[],"sources":["../../src/api/user.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport type { Request, Response } from 'express';\nimport { Router } from 'express';\nimport _ from 'lodash';\n\nimport { type Auth, getApiToken } from '@verdaccio/auth';\nimport type { VerdaccioError } from '@verdaccio/core';\nimport {\n API_ERROR,\n APP_ERROR,\n HEADERS,\n HTTP_STATUS,\n cryptoUtils,\n errorUtils,\n validationUtils,\n} from '@verdaccio/core';\nimport { WebUrls, rateLimit } from '@verdaccio/middleware';\nimport type { Config, JWTSignOptions, RemoteUser } from '@verdaccio/types';\n\nimport type { $NextFunctionVer } from './package';\n\nconst debug = buildDebug('verdaccio:web:api:user');\n\nconst WEB_LOGIN_SESSION_ID = 'web-login-sessionId';\n\nfunction addUserAuthApi(auth: Auth, config: Config, storage: Storage): Router {\n const route = Router(); /* eslint new-cap: 0 */\n route.post(\n WebUrls.user_login,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { username, password } = req.body;\n debug('authenticate %o', username);\n auth.authenticate(\n username,\n password,\n async (err: VerdaccioError | null, user?: RemoteUser): Promise<void> => {\n if (err) {\n const errorCode = err.message ? HTTP_STATUS.UNAUTHORIZED : HTTP_STATUS.INTERNAL_ERROR;\n debug('error authenticate %o', errorCode);\n next(errorUtils.getCode(errorCode, err.message));\n } else {\n req.remote_user = user as RemoteUser;\n const jWTSignOptions: JWTSignOptions = config.security.web.sign;\n res.set(HEADERS.CACHE_CONTROL, HEADERS.NO_CACHE);\n next({\n token: await auth.jwtEncrypt(user as RemoteUser, jWTSignOptions),\n username: req.remote_user.name,\n });\n }\n }\n );\n }\n );\n\n if (config?.flags?.createUser === true) {\n route.put(\n WebUrls.user_signup,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n const { name, password, email, sessionId } = req.body;\n debug('login or adduser');\n\n // TOOD: reuse with login.ts file\n if (typeof sessionId !== 'string' || sessionId.length !== 36) {\n debug('sessionId is invalid length: %o', sessionId.length);\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.SESSION_ID_INVALID));\n }\n\n if (!name || !password || !email) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, API_ERROR.BAD_DATA));\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 tokens = await storage.readTokens({ user: sessionId });\n debug('tokens found for sessionId %o: %o', sessionId, tokens.length);\n if (tokens && tokens.length === 1 && tokens[0].key === WEB_LOGIN_SESSION_ID) {\n if (tokens[0].token.length === 0) {\n debug('waiting for authentication');\n // Poll again after short delay\n // TODO: make this configurable (default 5 seconds)\n res.status(HTTP_STATUS.ACCEPTED);\n res.set(HEADERS.RETRY_AFTER, '5');\n res.json({});\n return;\n }\n\n // session token can only be used once\n debug('deleting session token');\n await storage.deleteToken(sessionId, tokens[0].key);\n\n // Check if token has expired\n // TODO: make this configurable (default 2 minutes)\n const tokenCreatedDate = new Date(tokens[0].created);\n const minutesAgo = new Date(Date.now() - 2 * 60 * 1000);\n if (tokenCreatedDate < minutesAgo) {\n debug('session token expired');\n return next(errorUtils.getUnauthorized(API_ERROR.SESSION_TOKEN_EXPIRED));\n }\n\n debug('session token is valid, login successful');\n res.status(HTTP_STATUS.OK);\n res.json({ token: tokens[0].token });\n return;\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', cryptoUtils.mask(token as string, 4));\n return next({ token, username: name });\n }\n return next(errorUtils.getUnauthorized());\n });\n }\n );\n }\n\n if (config?.flags?.changePassword === true) {\n route.put(\n WebUrls.reset_password,\n rateLimit(config?.userRateLimit),\n function (req: Request, res: Response, next: $NextFunctionVer): void {\n if (_.isNil(req.remote_user.name)) {\n res.status(HTTP_STATUS.UNAUTHORIZED);\n return next({\n // FUTURE: update to a more meaningful message\n message: API_ERROR.MUST_BE_LOGGED,\n });\n }\n\n const { password } = req.body;\n const { name } = req.remote_user;\n\n if (\n validationUtils.validatePassword(\n password.new,\n config?.server?.passwordValidationRegex\n ) === false\n ) {\n return next(errorUtils.getCode(HTTP_STATUS.BAD_REQUEST, APP_ERROR.PASSWORD_VALIDATION));\n }\n\n auth.changePassword(name as string, password.old, password.new, (err, isUpdated): void => {\n if (_.isNil(err) && isUpdated) {\n next({\n ok: true,\n });\n } else {\n return next(errorUtils.getInternalError(API_ERROR.INTERNAL_SERVER_ERROR));\n }\n });\n }\n );\n }\n\n return route;\n}\n\nexport default addUserAuthApi;\n"],"mappings":"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"}
package/build/index.js CHANGED
@@ -16,3 +16,4 @@ exports.generateGravatarUrl = require_author_utils.generateGravatarUrl;
16
16
  exports.hasLogin = require_web_utils.hasLogin;
17
17
  exports.isVersionValid = require_web_utils.isVersionValid;
18
18
  exports.sortByName = require_web_utils.sortByName;
19
+ exports.sortByTime = require_web_utils.sortByTime;
package/build/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { addScope, deleteProperties, hasLogin, isVersionValid, sortByName } from "./web-utils.mjs";
1
+ import { addScope, deleteProperties, hasLogin, isVersionValid, sortByName, sortByTime } from "./web-utils.mjs";
2
2
  import { GENERIC_AVATAR, addGravatarSupport, formatAuthor, generateGravatarUrl } from "./author-utils.mjs";
3
3
  import middleware_default, { DEFAULT_PLUGIN_UI_THEME } from "./middleware.mjs";
4
- export { DEFAULT_PLUGIN_UI_THEME, GENERIC_AVATAR, addGravatarSupport, addScope, middleware_default as default, deleteProperties, formatAuthor, generateGravatarUrl, hasLogin, isVersionValid, sortByName };
4
+ export { DEFAULT_PLUGIN_UI_THEME, GENERIC_AVATAR, addGravatarSupport, addScope, middleware_default as default, deleteProperties, formatAuthor, generateGravatarUrl, hasLogin, isVersionValid, sortByName, sortByTime };
@@ -1,6 +1,7 @@
1
1
  import { ConfigYaml, Manifest } from '@verdaccio/types';
2
2
  export declare function hasLogin(config: ConfigYaml): boolean;
3
3
  export declare function sortByName(packages: any[], orderAscending?: boolean | void): string[];
4
+ export declare function sortByTime(packages: any[], orderAscending?: boolean | void): string[];
4
5
  export declare function addScope(scope: string, packageName: string): string;
5
6
  export declare function deleteProperties(propertiesToDelete: string[], objectItem: any): any;
6
7
  export declare function isVersionValid(packageMeta: Manifest, packageVersion: string): boolean;
@@ -11,6 +11,12 @@ function sortByName(packages, orderAscending = true) {
11
11
  return orderAscending ? comparatorNames ? -1 : 1 : comparatorNames ? 1 : -1;
12
12
  });
13
13
  }
14
+ function sortByTime(packages, orderAscending = true) {
15
+ return packages.slice().sort(function(a, b) {
16
+ const comparatorTime = a.time < b.time;
17
+ return orderAscending ? comparatorTime ? -1 : 1 : comparatorTime ? 1 : -1;
18
+ });
19
+ }
14
20
  function addScope(scope, packageName) {
15
21
  return `@${scope}/${packageName}`;
16
22
  }
@@ -30,5 +36,6 @@ exports.deleteProperties = deleteProperties;
30
36
  exports.hasLogin = hasLogin;
31
37
  exports.isVersionValid = isVersionValid;
32
38
  exports.sortByName = sortByName;
39
+ exports.sortByTime = sortByTime;
33
40
 
34
41
  //# sourceMappingURL=web-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-utils.js","names":[],"sources":["../src/web-utils.ts"],"sourcesContent":["import _ from 'lodash';\n\nimport type { ConfigYaml, Manifest } from '@verdaccio/types';\n\nexport function hasLogin(config: ConfigYaml) {\n return _.isNil(config?.web?.login) || config?.web?.login === true;\n}\n\nexport function sortByName(packages: any[], orderAscending: boolean | void = true): string[] {\n return packages.slice().sort(function (a, b): number {\n const comparatorNames = a.name.toLowerCase() < b.name.toLowerCase();\n return orderAscending ? (comparatorNames ? -1 : 1) : comparatorNames ? 1 : -1;\n });\n}\n\nexport function addScope(scope: string, packageName: string): string {\n return `@${scope}/${packageName}`;\n}\n\nexport function deleteProperties(propertiesToDelete: string[], objectItem: any): any {\n _.forEach(propertiesToDelete, (property): any => {\n delete objectItem[property];\n });\n\n return objectItem;\n}\n\nexport function isVersionValid(packageMeta: Manifest, packageVersion: string): boolean {\n const hasVersion = typeof packageVersion !== 'undefined';\n if (!hasVersion) {\n return false;\n }\n\n const hasMatchVersion = Object.keys(packageMeta.versions).includes(packageVersion);\n return hasMatchVersion;\n}\n"],"mappings":";;;;AAIA,SAAgB,SAAS,QAAoB;AAC3C,QAAO,OAAA,QAAE,MAAM,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,UAAU;;AAG/D,SAAgB,WAAW,UAAiB,iBAAiC,MAAgB;AAC3F,QAAO,SAAS,OAAO,CAAC,KAAK,SAAU,GAAG,GAAW;EACnD,MAAM,kBAAkB,EAAE,KAAK,aAAa,GAAG,EAAE,KAAK,aAAa;AACnE,SAAO,iBAAkB,kBAAkB,KAAK,IAAK,kBAAkB,IAAI;GAC3E;;AAGJ,SAAgB,SAAS,OAAe,aAA6B;AACnE,QAAO,IAAI,MAAM,GAAG;;AAGtB,SAAgB,iBAAiB,oBAA8B,YAAsB;AACnF,QAAA,QAAE,QAAQ,qBAAqB,aAAkB;AAC/C,SAAO,WAAW;GAClB;AAEF,QAAO;;AAGT,SAAgB,eAAe,aAAuB,gBAAiC;AAErF,KAAI,EADe,OAAO,mBAAmB,aAE3C,QAAO;AAIT,QADwB,OAAO,KAAK,YAAY,SAAS,CAAC,SAAS,eAAe"}
1
+ {"version":3,"file":"web-utils.js","names":[],"sources":["../src/web-utils.ts"],"sourcesContent":["import _ from 'lodash';\n\nimport type { ConfigYaml, Manifest } from '@verdaccio/types';\n\nexport function hasLogin(config: ConfigYaml) {\n return _.isNil(config?.web?.login) || config?.web?.login === true;\n}\n\nexport function sortByName(packages: any[], orderAscending: boolean | void = true): string[] {\n return packages.slice().sort(function (a, b): number {\n const comparatorNames = a.name.toLowerCase() < b.name.toLowerCase();\n return orderAscending ? (comparatorNames ? -1 : 1) : comparatorNames ? 1 : -1;\n });\n}\n\nexport function sortByTime(packages: any[], orderAscending: boolean | void = true): string[] {\n return packages.slice().sort(function (a, b): number {\n const comparatorTime = a.time < b.time;\n return orderAscending ? (comparatorTime ? -1 : 1) : comparatorTime ? 1 : -1;\n });\n}\n\nexport function addScope(scope: string, packageName: string): string {\n return `@${scope}/${packageName}`;\n}\n\nexport function deleteProperties(propertiesToDelete: string[], objectItem: any): any {\n _.forEach(propertiesToDelete, (property): any => {\n delete objectItem[property];\n });\n\n return objectItem;\n}\n\nexport function isVersionValid(packageMeta: Manifest, packageVersion: string): boolean {\n const hasVersion = typeof packageVersion !== 'undefined';\n if (!hasVersion) {\n return false;\n }\n\n const hasMatchVersion = Object.keys(packageMeta.versions).includes(packageVersion);\n return hasMatchVersion;\n}\n"],"mappings":";;;;AAIA,SAAgB,SAAS,QAAoB;AAC3C,QAAO,OAAA,QAAE,MAAM,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,UAAU;;AAG/D,SAAgB,WAAW,UAAiB,iBAAiC,MAAgB;AAC3F,QAAO,SAAS,OAAO,CAAC,KAAK,SAAU,GAAG,GAAW;EACnD,MAAM,kBAAkB,EAAE,KAAK,aAAa,GAAG,EAAE,KAAK,aAAa;AACnE,SAAO,iBAAkB,kBAAkB,KAAK,IAAK,kBAAkB,IAAI;GAC3E;;AAGJ,SAAgB,WAAW,UAAiB,iBAAiC,MAAgB;AAC3F,QAAO,SAAS,OAAO,CAAC,KAAK,SAAU,GAAG,GAAW;EACnD,MAAM,iBAAiB,EAAE,OAAO,EAAE;AAClC,SAAO,iBAAkB,iBAAiB,KAAK,IAAK,iBAAiB,IAAI;GACzE;;AAGJ,SAAgB,SAAS,OAAe,aAA6B;AACnE,QAAO,IAAI,MAAM,GAAG;;AAGtB,SAAgB,iBAAiB,oBAA8B,YAAsB;AACnF,QAAA,QAAE,QAAQ,qBAAqB,aAAkB;AAC/C,SAAO,WAAW;GAClB;AAEF,QAAO;;AAGT,SAAgB,eAAe,aAAuB,gBAAiC;AAErF,KAAI,EADe,OAAO,mBAAmB,aAE3C,QAAO;AAIT,QADwB,OAAO,KAAK,YAAY,SAAS,CAAC,SAAS,eAAe"}
@@ -9,6 +9,12 @@ function sortByName(packages, orderAscending = true) {
9
9
  return orderAscending ? comparatorNames ? -1 : 1 : comparatorNames ? 1 : -1;
10
10
  });
11
11
  }
12
+ function sortByTime(packages, orderAscending = true) {
13
+ return packages.slice().sort(function(a, b) {
14
+ const comparatorTime = a.time < b.time;
15
+ return orderAscending ? comparatorTime ? -1 : 1 : comparatorTime ? 1 : -1;
16
+ });
17
+ }
12
18
  function addScope(scope, packageName) {
13
19
  return `@${scope}/${packageName}`;
14
20
  }
@@ -23,6 +29,6 @@ function isVersionValid(packageMeta, packageVersion) {
23
29
  return Object.keys(packageMeta.versions).includes(packageVersion);
24
30
  }
25
31
  //#endregion
26
- export { addScope, deleteProperties, hasLogin, isVersionValid, sortByName };
32
+ export { addScope, deleteProperties, hasLogin, isVersionValid, sortByName, sortByTime };
27
33
 
28
34
  //# sourceMappingURL=web-utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-utils.mjs","names":[],"sources":["../src/web-utils.ts"],"sourcesContent":["import _ from 'lodash';\n\nimport type { ConfigYaml, Manifest } from '@verdaccio/types';\n\nexport function hasLogin(config: ConfigYaml) {\n return _.isNil(config?.web?.login) || config?.web?.login === true;\n}\n\nexport function sortByName(packages: any[], orderAscending: boolean | void = true): string[] {\n return packages.slice().sort(function (a, b): number {\n const comparatorNames = a.name.toLowerCase() < b.name.toLowerCase();\n return orderAscending ? (comparatorNames ? -1 : 1) : comparatorNames ? 1 : -1;\n });\n}\n\nexport function addScope(scope: string, packageName: string): string {\n return `@${scope}/${packageName}`;\n}\n\nexport function deleteProperties(propertiesToDelete: string[], objectItem: any): any {\n _.forEach(propertiesToDelete, (property): any => {\n delete objectItem[property];\n });\n\n return objectItem;\n}\n\nexport function isVersionValid(packageMeta: Manifest, packageVersion: string): boolean {\n const hasVersion = typeof packageVersion !== 'undefined';\n if (!hasVersion) {\n return false;\n }\n\n const hasMatchVersion = Object.keys(packageMeta.versions).includes(packageVersion);\n return hasMatchVersion;\n}\n"],"mappings":";;AAIA,SAAgB,SAAS,QAAoB;AAC3C,QAAO,EAAE,MAAM,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,UAAU;;AAG/D,SAAgB,WAAW,UAAiB,iBAAiC,MAAgB;AAC3F,QAAO,SAAS,OAAO,CAAC,KAAK,SAAU,GAAG,GAAW;EACnD,MAAM,kBAAkB,EAAE,KAAK,aAAa,GAAG,EAAE,KAAK,aAAa;AACnE,SAAO,iBAAkB,kBAAkB,KAAK,IAAK,kBAAkB,IAAI;GAC3E;;AAGJ,SAAgB,SAAS,OAAe,aAA6B;AACnE,QAAO,IAAI,MAAM,GAAG;;AAGtB,SAAgB,iBAAiB,oBAA8B,YAAsB;AACnF,GAAE,QAAQ,qBAAqB,aAAkB;AAC/C,SAAO,WAAW;GAClB;AAEF,QAAO;;AAGT,SAAgB,eAAe,aAAuB,gBAAiC;AAErF,KAAI,EADe,OAAO,mBAAmB,aAE3C,QAAO;AAIT,QADwB,OAAO,KAAK,YAAY,SAAS,CAAC,SAAS,eAAe"}
1
+ {"version":3,"file":"web-utils.mjs","names":[],"sources":["../src/web-utils.ts"],"sourcesContent":["import _ from 'lodash';\n\nimport type { ConfigYaml, Manifest } from '@verdaccio/types';\n\nexport function hasLogin(config: ConfigYaml) {\n return _.isNil(config?.web?.login) || config?.web?.login === true;\n}\n\nexport function sortByName(packages: any[], orderAscending: boolean | void = true): string[] {\n return packages.slice().sort(function (a, b): number {\n const comparatorNames = a.name.toLowerCase() < b.name.toLowerCase();\n return orderAscending ? (comparatorNames ? -1 : 1) : comparatorNames ? 1 : -1;\n });\n}\n\nexport function sortByTime(packages: any[], orderAscending: boolean | void = true): string[] {\n return packages.slice().sort(function (a, b): number {\n const comparatorTime = a.time < b.time;\n return orderAscending ? (comparatorTime ? -1 : 1) : comparatorTime ? 1 : -1;\n });\n}\n\nexport function addScope(scope: string, packageName: string): string {\n return `@${scope}/${packageName}`;\n}\n\nexport function deleteProperties(propertiesToDelete: string[], objectItem: any): any {\n _.forEach(propertiesToDelete, (property): any => {\n delete objectItem[property];\n });\n\n return objectItem;\n}\n\nexport function isVersionValid(packageMeta: Manifest, packageVersion: string): boolean {\n const hasVersion = typeof packageVersion !== 'undefined';\n if (!hasVersion) {\n return false;\n }\n\n const hasMatchVersion = Object.keys(packageMeta.versions).includes(packageVersion);\n return hasMatchVersion;\n}\n"],"mappings":";;AAIA,SAAgB,SAAS,QAAoB;AAC3C,QAAO,EAAE,MAAM,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,UAAU;;AAG/D,SAAgB,WAAW,UAAiB,iBAAiC,MAAgB;AAC3F,QAAO,SAAS,OAAO,CAAC,KAAK,SAAU,GAAG,GAAW;EACnD,MAAM,kBAAkB,EAAE,KAAK,aAAa,GAAG,EAAE,KAAK,aAAa;AACnE,SAAO,iBAAkB,kBAAkB,KAAK,IAAK,kBAAkB,IAAI;GAC3E;;AAGJ,SAAgB,WAAW,UAAiB,iBAAiC,MAAgB;AAC3F,QAAO,SAAS,OAAO,CAAC,KAAK,SAAU,GAAG,GAAW;EACnD,MAAM,iBAAiB,EAAE,OAAO,EAAE;AAClC,SAAO,iBAAkB,iBAAiB,KAAK,IAAK,iBAAiB,IAAI;GACzE;;AAGJ,SAAgB,SAAS,OAAe,aAA6B;AACnE,QAAO,IAAI,MAAM,GAAG;;AAGtB,SAAgB,iBAAiB,oBAA8B,YAAsB;AACnF,GAAE,QAAQ,qBAAqB,aAAkB;AAC/C,SAAO,WAAW;GAClB;AAEF,QAAO;;AAGT,SAAgB,eAAe,aAAuB,gBAAiC;AAErF,KAAI,EADe,OAAO,mBAAmB,aAE3C,QAAO;AAIT,QADwB,OAAO,KAAK,YAAY,SAAS,CAAC,SAAS,eAAe"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/web",
3
- "version": "9.0.0-next-9.4",
3
+ "version": "9.0.0-next-9.6",
4
4
  "description": "Verdaccio Web Middleware",
5
5
  "main": "./build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -28,25 +28,25 @@
28
28
  },
29
29
  "license": "MIT",
30
30
  "dependencies": {
31
- "@verdaccio/auth": "9.0.0-next-9.4",
32
- "@verdaccio/config": "9.0.0-next-9.4",
33
- "@verdaccio/core": "9.0.0-next-9.4",
34
- "@verdaccio/loaders": "9.0.0-next-9.4",
35
- "@verdaccio/logger": "9.0.0-next-9.4",
36
- "@verdaccio/middleware": "9.0.0-next-9.4",
37
- "@verdaccio/store": "9.0.0-next-9.4",
38
- "@verdaccio/tarball": "14.0.0-next-9.4",
31
+ "@verdaccio/auth": "9.0.0-next-9.6",
32
+ "@verdaccio/config": "9.0.0-next-9.6",
33
+ "@verdaccio/core": "9.0.0-next-9.6",
34
+ "@verdaccio/loaders": "9.0.0-next-9.6",
35
+ "@verdaccio/logger": "9.0.0-next-9.6",
36
+ "@verdaccio/middleware": "9.0.0-next-9.6",
37
+ "@verdaccio/store": "9.0.0-next-9.6",
38
+ "@verdaccio/tarball": "14.0.0-next-9.6",
39
39
  "debug": "4.4.3",
40
40
  "express": "5.2.1",
41
41
  "lodash": "4.17.23"
42
42
  },
43
43
  "devDependencies": {
44
- "@verdaccio/api": "9.0.0-next-9.4",
45
- "@verdaccio/test-helper": "5.0.0-next-9.4",
46
- "@verdaccio/types": "14.0.0-next-9.1",
44
+ "@verdaccio/api": "9.0.0-next-9.6",
45
+ "@verdaccio/test-helper": "5.0.0-next-9.6",
46
+ "@verdaccio/types": "14.0.0-next-9.3",
47
47
  "jsdom": "28.1.0",
48
48
  "supertest": "7.1.4",
49
- "vitest": "3.2.4"
49
+ "vitest": "4.1.0"
50
50
  },
51
51
  "funding": {
52
52
  "type": "opencollective",