@verdaccio/core 8.3.1 → 8.3.2

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.
@@ -1,6 +1,8 @@
1
1
  import type { Manifest } from '@verdaccio/types';
2
2
  export { validatePublishSingleVersion } from './schemes/publish-manifest';
3
3
  export { validateUnPublishSingleVersion } from './schemes/unpublish-manifest';
4
+ /** Package name rules for existing packages; a leading hyphen stays valid. */
5
+ export declare function validatePackageName(name: unknown): boolean;
4
6
  export declare function isPackageNameScoped(name: string): boolean;
5
7
  /**
6
8
  * From normalize-package-data/lib/fixer.js
@@ -11,11 +11,32 @@ var validation_utils_exports = /* @__PURE__ */ require_runtime.__exportAll({
11
11
  normalizeMetadata: () => normalizeMetadata,
12
12
  validateName: () => validateName,
13
13
  validatePackage: () => validatePackage,
14
+ validatePackageName: () => validatePackageName,
14
15
  validatePassword: () => validatePassword,
15
16
  validatePublishSingleVersion: () => require_publish_manifest.validatePublishSingleVersion,
16
17
  validateUnPublishSingleVersion: () => require_unpublish_manifest.validateUnPublishSingleVersion,
17
18
  validateUserName: () => validateUserName
18
19
  });
20
+ var scopedPackagePattern = /^(?:@([^/]+?)[/])?([^/]+?)$/;
21
+ var exclusionList = ["node_modules", "favicon.ico"];
22
+ function isUrlFriendly(value) {
23
+ try {
24
+ return encodeURIComponent(value) === value;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+ /** Package name rules for existing packages; a leading hyphen stays valid. */
30
+ function validatePackageName(name) {
31
+ if (typeof name !== "string" || !name.length) return false;
32
+ if (name.startsWith(".") || name.startsWith("_") || name.trim() !== name) return false;
33
+ if (exclusionList.includes(name.toLowerCase())) return false;
34
+ if (isUrlFriendly(name)) return true;
35
+ const nameMatch = name.match(scopedPackagePattern);
36
+ if (!nameMatch) return false;
37
+ const [, user, pkg] = nameMatch;
38
+ return user !== void 0 && isUrlFriendly(user) && !pkg.startsWith(".") && isUrlFriendly(pkg);
39
+ }
19
40
  function isPackageNameScoped(name) {
20
41
  return name.startsWith("@");
21
42
  }
@@ -50,6 +71,10 @@ function validateName(name) {
50
71
  * @return {Boolean} whether the package is valid or not
51
72
  */
52
73
  function validatePackage(name) {
74
+ if (!isValidPackagePath(name)) return false;
75
+ return validatePackageName(name);
76
+ }
77
+ function isValidPackagePath(name) {
53
78
  const nameList = name.split("/");
54
79
  if (nameList.length === 1) return validateName(nameList[0]);
55
80
  else if (nameList.length === 2) return nameList[0][0] === "@" && validateName(nameList[0].slice(1)) && validateName(nameList[1]);
@@ -91,6 +116,7 @@ exports.isPackageNameScoped = isPackageNameScoped;
91
116
  exports.normalizeMetadata = normalizeMetadata;
92
117
  exports.validateName = validateName;
93
118
  exports.validatePackage = validatePackage;
119
+ exports.validatePackageName = validatePackageName;
94
120
  exports.validatePassword = validatePassword;
95
121
  exports.validatePublishSingleVersion = require_publish_manifest.validatePublishSingleVersion;
96
122
  exports.validateUnPublishSingleVersion = require_unpublish_manifest.validateUnPublishSingleVersion;
@@ -1 +1 @@
1
- {"version":3,"file":"validation-utils.js","names":[],"sources":["../src/validation-utils.ts"],"sourcesContent":["import assert from 'node:assert';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { DEFAULT_PASSWORD_VALIDATION, DIST_TAGS, MAINTAINERS } from './constants';\n\nexport { validatePublishSingleVersion } from './schemes/publish-manifest';\nexport { validateUnPublishSingleVersion } from './schemes/unpublish-manifest';\n\nexport function isPackageNameScoped(name: string): boolean {\n return name.startsWith('@');\n}\n\n/**\n * From normalize-package-data/lib/fixer.js\n * @param {*} name the package name\n * @return {Boolean} whether is valid or not\n */\nexport function validateName(name: string): boolean {\n if (typeof name !== 'string') {\n return false;\n }\n\n if (isPackageNameScoped(name) && name.includes('/')) {\n return validatePackage(name);\n }\n\n const normalizedName: string = name.toLowerCase();\n\n /**\n * Some context about the first regex\n * - npm used to have a different tarball naming system.\n * eg: http://registry.npmjs.com/thirty-two\n * https://registry.npmjs.org/thirty-two/-/thirty-two@0.0.1.tgz\n * The file name thirty-two@0.0.1.tgz, the version and the pkg name was separated by an at (@)\n * while nowadays the naming system is based in dashes\n * https://registry.npmjs.org/verdaccio/-/verdaccio-1.4.0.tgz\n *\n * more info here: https://github.com/rlidwka/sinopia/issues/75\n */\n return !(\n !normalizedName.match(/^[-a-zA-Z0-9_.!~*'()@]+$/) ||\n normalizedName.startsWith('.') || // \".bin\", etc.\n ['node_modules', '__proto__', 'favicon.ico'].includes(normalizedName)\n );\n}\n\n/**\n * Validate a package.\n * @return {Boolean} whether the package is valid or not\n */\nexport function validatePackage(name: string): boolean {\n // Split on every separator (no limit) so trailing or interior slashes are not\n // silently dropped, keeping a single canonical form per package name.\n const nameList = name.split('/');\n if (nameList.length === 1) {\n // normal package\n return validateName(nameList[0]);\n } else if (nameList.length === 2) {\n // scoped package\n return (\n nameList[0][0] === '@' && validateName(nameList[0].slice(1)) && validateName(nameList[1])\n );\n }\n // anything with 3+ segments is never a valid package name\n return false;\n}\n\n/**\n * Validate the package metadata, add additional properties whether are missing within\n * the metadata properties.\n * @param {*} manifest\n * @param {*} name\n * @return {Object} the object with additional properties as dist-tags ad versions\n */\nexport function normalizeMetadata(manifest: Manifest, name: string): Manifest {\n assert.strictEqual(manifest.name, name);\n const _manifest = { ...manifest };\n\n if (!isObject(manifest[DIST_TAGS])) {\n _manifest[DIST_TAGS] = {};\n }\n\n if (!Array.isArray(manifest[MAINTAINERS])) {\n _manifest[MAINTAINERS] = [];\n }\n\n // This may not be needed\n if (!isObject(manifest['versions'])) {\n _manifest['versions'] = {};\n }\n\n if (!isObject(manifest['time'])) {\n _manifest['time'] = {};\n }\n\n return _manifest;\n}\n\n/**\n * Check whether an element is an Object\n * @param {*} obj the element\n * @return {Boolean}\n */\nexport function isObject(obj: any): boolean {\n // if (obj === null || typeof obj === 'undefined' || typeof obj === 'string') {\n // return false;\n // }\n\n // return (\n // (typeof obj === 'object' || typeof obj.prototype === 'undefined') &&\n // Array.isArray(obj) === false\n // );\n return Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function validatePassword(\n password: string,\n validation: RegExp = DEFAULT_PASSWORD_VALIDATION\n): boolean {\n return typeof password === 'string' && validation instanceof RegExp\n ? password.match(validation) !== null\n : false;\n}\n\nexport function validateUserName(userName: any, expectedName: string): boolean {\n return (\n typeof userName === 'string' &&\n userName.split(':')[0] === 'org.couchdb.user' &&\n userName.split(':')[1] === expectedName\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AASA,SAAgB,oBAAoB,MAAuB;CACzD,OAAO,KAAK,WAAW,GAAG;AAC5B;;;;;;AAOA,SAAgB,aAAa,MAAuB;CAClD,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,IAAI,oBAAoB,IAAI,KAAK,KAAK,SAAS,GAAG,GAChD,OAAO,gBAAgB,IAAI;CAG7B,MAAM,iBAAyB,KAAK,YAAY;;;;;;;;;;;;CAahD,OAAO,EACL,CAAC,eAAe,MAAM,0BAA0B,KAChD,eAAe,WAAW,GAAG,KAC7B;EAAC;EAAgB;EAAa;CAAa,CAAC,CAAC,SAAS,cAAc;AAExE;;;;;AAMA,SAAgB,gBAAgB,MAAuB;CAGrD,MAAM,WAAW,KAAK,MAAM,GAAG;CAC/B,IAAI,SAAS,WAAW,GAEtB,OAAO,aAAa,SAAS,EAAE;MAC1B,IAAI,SAAS,WAAW,GAE7B,OACE,SAAS,EAAE,CAAC,OAAO,OAAO,aAAa,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,aAAa,SAAS,EAAE;CAI5F,OAAO;AACT;;;;;;;;AASA,SAAgB,kBAAkB,UAAoB,MAAwB;CAC5E,YAAA,QAAO,YAAY,SAAS,MAAM,IAAI;CACtC,MAAM,YAAY,EAAE,GAAG,SAAS;CAEhC,IAAI,CAAC,SAAS,SAAA,YAAmB,GAC/B,UAAU,kBAAA,aAAa,CAAC;CAG1B,IAAI,CAAC,MAAM,QAAQ,SAAA,cAAqB,GACtC,UAAU,kBAAA,eAAe,CAAC;CAI5B,IAAI,CAAC,SAAS,SAAS,WAAW,GAChC,UAAU,cAAc,CAAC;CAG3B,IAAI,CAAC,SAAS,SAAS,OAAO,GAC5B,UAAU,UAAU,CAAC;CAGvB,OAAO;AACT;;;;;;AAOA,SAAgB,SAAS,KAAmB;CAS1C,OAAO,OAAO,UAAU,SAAS,KAAK,GAAG,MAAM;AACjD;AAEA,SAAgB,iBACd,UACA,aAAqB,kBAAA,6BACZ;CACT,OAAO,OAAO,aAAa,YAAY,sBAAsB,SACzD,SAAS,MAAM,UAAU,MAAM,OAC/B;AACN;AAEA,SAAgB,iBAAiB,UAAe,cAA+B;CAC7E,OACE,OAAO,aAAa,YACpB,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO,sBAC3B,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO;AAE/B"}
1
+ {"version":3,"file":"validation-utils.js","names":[],"sources":["../src/validation-utils.ts"],"sourcesContent":["import assert from 'node:assert';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { DEFAULT_PASSWORD_VALIDATION, DIST_TAGS, MAINTAINERS } from './constants';\n\nexport { validatePublishSingleVersion } from './schemes/publish-manifest';\nexport { validateUnPublishSingleVersion } from './schemes/unpublish-manifest';\n\nconst scopedPackagePattern = /^(?:@([^/]+?)[/])?([^/]+?)$/;\nconst exclusionList = ['node_modules', 'favicon.ico'];\n\n// encodeURIComponent throws on malformed UTF-16, such as a lone surrogate\nfunction isUrlFriendly(value: string): boolean {\n try {\n return encodeURIComponent(value) === value;\n } catch {\n return false;\n }\n}\n\n/** Package name rules for existing packages; a leading hyphen stays valid. */\nexport function validatePackageName(name: unknown): boolean {\n if (typeof name !== 'string' || !name.length) {\n return false;\n }\n if (name.startsWith('.') || name.startsWith('_') || name.trim() !== name) {\n return false;\n }\n if (exclusionList.includes(name.toLowerCase())) {\n return false;\n }\n if (isUrlFriendly(name)) {\n return true;\n }\n const nameMatch = name.match(scopedPackagePattern);\n if (!nameMatch) {\n return false;\n }\n const [, user, pkg] = nameMatch;\n return user !== undefined && isUrlFriendly(user) && !pkg.startsWith('.') && isUrlFriendly(pkg);\n}\n\nexport function isPackageNameScoped(name: string): boolean {\n return name.startsWith('@');\n}\n\n/**\n * From normalize-package-data/lib/fixer.js\n * @param {*} name the package name\n * @return {Boolean} whether is valid or not\n */\nexport function validateName(name: string): boolean {\n if (typeof name !== 'string') {\n return false;\n }\n\n if (isPackageNameScoped(name) && name.includes('/')) {\n return validatePackage(name);\n }\n\n const normalizedName: string = name.toLowerCase();\n\n /**\n * Some context about the first regex\n * - npm used to have a different tarball naming system.\n * eg: http://registry.npmjs.com/thirty-two\n * https://registry.npmjs.org/thirty-two/-/thirty-two@0.0.1.tgz\n * The file name thirty-two@0.0.1.tgz, the version and the pkg name was separated by an at (@)\n * while nowadays the naming system is based in dashes\n * https://registry.npmjs.org/verdaccio/-/verdaccio-1.4.0.tgz\n *\n * more info here: https://github.com/rlidwka/sinopia/issues/75\n */\n return !(\n !normalizedName.match(/^[-a-zA-Z0-9_.!~*'()@]+$/) ||\n normalizedName.startsWith('.') || // \".bin\", etc.\n ['node_modules', '__proto__', 'favicon.ico'].includes(normalizedName)\n );\n}\n\n/**\n * Validate a package.\n * @return {Boolean} whether the package is valid or not\n */\nexport function validatePackage(name: string): boolean {\n if (!isValidPackagePath(name)) {\n return false;\n }\n return validatePackageName(name);\n}\n\nfunction isValidPackagePath(name: string): boolean {\n // Split on every separator (no limit) so trailing or interior slashes are not\n // silently dropped, keeping a single canonical form per package name.\n const nameList = name.split('/');\n if (nameList.length === 1) {\n // normal package\n return validateName(nameList[0]);\n } else if (nameList.length === 2) {\n // scoped package\n return (\n nameList[0][0] === '@' && validateName(nameList[0].slice(1)) && validateName(nameList[1])\n );\n }\n // anything with 3+ segments is never a valid package name\n return false;\n}\n\n/**\n * Validate the package metadata, add additional properties whether are missing within\n * the metadata properties.\n * @param {*} manifest\n * @param {*} name\n * @return {Object} the object with additional properties as dist-tags ad versions\n */\nexport function normalizeMetadata(manifest: Manifest, name: string): Manifest {\n assert.strictEqual(manifest.name, name);\n const _manifest = { ...manifest };\n\n if (!isObject(manifest[DIST_TAGS])) {\n _manifest[DIST_TAGS] = {};\n }\n\n if (!Array.isArray(manifest[MAINTAINERS])) {\n _manifest[MAINTAINERS] = [];\n }\n\n // This may not be needed\n if (!isObject(manifest['versions'])) {\n _manifest['versions'] = {};\n }\n\n if (!isObject(manifest['time'])) {\n _manifest['time'] = {};\n }\n\n return _manifest;\n}\n\n/**\n * Check whether an element is an Object\n * @param {*} obj the element\n * @return {Boolean}\n */\nexport function isObject(obj: any): boolean {\n // if (obj === null || typeof obj === 'undefined' || typeof obj === 'string') {\n // return false;\n // }\n\n // return (\n // (typeof obj === 'object' || typeof obj.prototype === 'undefined') &&\n // Array.isArray(obj) === false\n // );\n return Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function validatePassword(\n password: string,\n validation: RegExp = DEFAULT_PASSWORD_VALIDATION\n): boolean {\n return typeof password === 'string' && validation instanceof RegExp\n ? password.match(validation) !== null\n : false;\n}\n\nexport function validateUserName(userName: any, expectedName: string): boolean {\n return (\n typeof userName === 'string' &&\n userName.split(':')[0] === 'org.couchdb.user' &&\n userName.split(':')[1] === expectedName\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AASA,IAAM,uBAAuB;AAC7B,IAAM,gBAAgB,CAAC,gBAAgB,aAAa;AAGpD,SAAS,cAAc,OAAwB;CAC7C,IAAI;EACF,OAAO,mBAAmB,KAAK,MAAM;CACvC,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,SAAgB,oBAAoB,MAAwB;CAC1D,IAAI,OAAO,SAAS,YAAY,CAAC,KAAK,QACpC,OAAO;CAET,IAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,KAAK,MAAM,MAClE,OAAO;CAET,IAAI,cAAc,SAAS,KAAK,YAAY,CAAC,GAC3C,OAAO;CAET,IAAI,cAAc,IAAI,GACpB,OAAO;CAET,MAAM,YAAY,KAAK,MAAM,oBAAoB;CACjD,IAAI,CAAC,WACH,OAAO;CAET,MAAM,GAAG,MAAM,OAAO;CACtB,OAAO,SAAS,KAAA,KAAa,cAAc,IAAI,KAAK,CAAC,IAAI,WAAW,GAAG,KAAK,cAAc,GAAG;AAC/F;AAEA,SAAgB,oBAAoB,MAAuB;CACzD,OAAO,KAAK,WAAW,GAAG;AAC5B;;;;;;AAOA,SAAgB,aAAa,MAAuB;CAClD,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,IAAI,oBAAoB,IAAI,KAAK,KAAK,SAAS,GAAG,GAChD,OAAO,gBAAgB,IAAI;CAG7B,MAAM,iBAAyB,KAAK,YAAY;;;;;;;;;;;;CAahD,OAAO,EACL,CAAC,eAAe,MAAM,0BAA0B,KAChD,eAAe,WAAW,GAAG,KAC7B;EAAC;EAAgB;EAAa;CAAa,CAAC,CAAC,SAAS,cAAc;AAExE;;;;;AAMA,SAAgB,gBAAgB,MAAuB;CACrD,IAAI,CAAC,mBAAmB,IAAI,GAC1B,OAAO;CAET,OAAO,oBAAoB,IAAI;AACjC;AAEA,SAAS,mBAAmB,MAAuB;CAGjD,MAAM,WAAW,KAAK,MAAM,GAAG;CAC/B,IAAI,SAAS,WAAW,GAEtB,OAAO,aAAa,SAAS,EAAE;MAC1B,IAAI,SAAS,WAAW,GAE7B,OACE,SAAS,EAAE,CAAC,OAAO,OAAO,aAAa,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,aAAa,SAAS,EAAE;CAI5F,OAAO;AACT;;;;;;;;AASA,SAAgB,kBAAkB,UAAoB,MAAwB;CAC5E,YAAA,QAAO,YAAY,SAAS,MAAM,IAAI;CACtC,MAAM,YAAY,EAAE,GAAG,SAAS;CAEhC,IAAI,CAAC,SAAS,SAAA,YAAmB,GAC/B,UAAU,kBAAA,aAAa,CAAC;CAG1B,IAAI,CAAC,MAAM,QAAQ,SAAA,cAAqB,GACtC,UAAU,kBAAA,eAAe,CAAC;CAI5B,IAAI,CAAC,SAAS,SAAS,WAAW,GAChC,UAAU,cAAc,CAAC;CAG3B,IAAI,CAAC,SAAS,SAAS,OAAO,GAC5B,UAAU,UAAU,CAAC;CAGvB,OAAO;AACT;;;;;;AAOA,SAAgB,SAAS,KAAmB;CAS1C,OAAO,OAAO,UAAU,SAAS,KAAK,GAAG,MAAM;AACjD;AAEA,SAAgB,iBACd,UACA,aAAqB,kBAAA,6BACZ;CACT,OAAO,OAAO,aAAa,YAAY,sBAAsB,SACzD,SAAS,MAAM,UAAU,MAAM,OAC/B;AACN;AAEA,SAAgB,iBAAiB,UAAe,cAA+B;CAC7E,OACE,OAAO,aAAa,YACpB,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO,sBAC3B,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO;AAE/B"}
@@ -10,11 +10,32 @@ var validation_utils_exports = /* @__PURE__ */ __exportAll({
10
10
  normalizeMetadata: () => normalizeMetadata,
11
11
  validateName: () => validateName,
12
12
  validatePackage: () => validatePackage,
13
+ validatePackageName: () => validatePackageName,
13
14
  validatePassword: () => validatePassword,
14
15
  validatePublishSingleVersion: () => validatePublishSingleVersion,
15
16
  validateUnPublishSingleVersion: () => validateUnPublishSingleVersion,
16
17
  validateUserName: () => validateUserName
17
18
  });
19
+ var scopedPackagePattern = /^(?:@([^/]+?)[/])?([^/]+?)$/;
20
+ var exclusionList = ["node_modules", "favicon.ico"];
21
+ function isUrlFriendly(value) {
22
+ try {
23
+ return encodeURIComponent(value) === value;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+ /** Package name rules for existing packages; a leading hyphen stays valid. */
29
+ function validatePackageName(name) {
30
+ if (typeof name !== "string" || !name.length) return false;
31
+ if (name.startsWith(".") || name.startsWith("_") || name.trim() !== name) return false;
32
+ if (exclusionList.includes(name.toLowerCase())) return false;
33
+ if (isUrlFriendly(name)) return true;
34
+ const nameMatch = name.match(scopedPackagePattern);
35
+ if (!nameMatch) return false;
36
+ const [, user, pkg] = nameMatch;
37
+ return user !== void 0 && isUrlFriendly(user) && !pkg.startsWith(".") && isUrlFriendly(pkg);
38
+ }
18
39
  function isPackageNameScoped(name) {
19
40
  return name.startsWith("@");
20
41
  }
@@ -49,6 +70,10 @@ function validateName(name) {
49
70
  * @return {Boolean} whether the package is valid or not
50
71
  */
51
72
  function validatePackage(name) {
73
+ if (!isValidPackagePath(name)) return false;
74
+ return validatePackageName(name);
75
+ }
76
+ function isValidPackagePath(name) {
52
77
  const nameList = name.split("/");
53
78
  if (nameList.length === 1) return validateName(nameList[0]);
54
79
  else if (nameList.length === 2) return nameList[0][0] === "@" && validateName(nameList[0].slice(1)) && validateName(nameList[1]);
@@ -85,6 +110,6 @@ function validateUserName(userName, expectedName) {
85
110
  return typeof userName === "string" && userName.split(":")[0] === "org.couchdb.user" && userName.split(":")[1] === expectedName;
86
111
  }
87
112
  //#endregion
88
- export { isObject, isPackageNameScoped, normalizeMetadata, validateName, validatePackage, validatePassword, validatePublishSingleVersion, validateUnPublishSingleVersion, validateUserName, validation_utils_exports };
113
+ export { isObject, isPackageNameScoped, normalizeMetadata, validateName, validatePackage, validatePackageName, validatePassword, validatePublishSingleVersion, validateUnPublishSingleVersion, validateUserName, validation_utils_exports };
89
114
 
90
115
  //# sourceMappingURL=validation-utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation-utils.mjs","names":[],"sources":["../src/validation-utils.ts"],"sourcesContent":["import assert from 'node:assert';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { DEFAULT_PASSWORD_VALIDATION, DIST_TAGS, MAINTAINERS } from './constants';\n\nexport { validatePublishSingleVersion } from './schemes/publish-manifest';\nexport { validateUnPublishSingleVersion } from './schemes/unpublish-manifest';\n\nexport function isPackageNameScoped(name: string): boolean {\n return name.startsWith('@');\n}\n\n/**\n * From normalize-package-data/lib/fixer.js\n * @param {*} name the package name\n * @return {Boolean} whether is valid or not\n */\nexport function validateName(name: string): boolean {\n if (typeof name !== 'string') {\n return false;\n }\n\n if (isPackageNameScoped(name) && name.includes('/')) {\n return validatePackage(name);\n }\n\n const normalizedName: string = name.toLowerCase();\n\n /**\n * Some context about the first regex\n * - npm used to have a different tarball naming system.\n * eg: http://registry.npmjs.com/thirty-two\n * https://registry.npmjs.org/thirty-two/-/thirty-two@0.0.1.tgz\n * The file name thirty-two@0.0.1.tgz, the version and the pkg name was separated by an at (@)\n * while nowadays the naming system is based in dashes\n * https://registry.npmjs.org/verdaccio/-/verdaccio-1.4.0.tgz\n *\n * more info here: https://github.com/rlidwka/sinopia/issues/75\n */\n return !(\n !normalizedName.match(/^[-a-zA-Z0-9_.!~*'()@]+$/) ||\n normalizedName.startsWith('.') || // \".bin\", etc.\n ['node_modules', '__proto__', 'favicon.ico'].includes(normalizedName)\n );\n}\n\n/**\n * Validate a package.\n * @return {Boolean} whether the package is valid or not\n */\nexport function validatePackage(name: string): boolean {\n // Split on every separator (no limit) so trailing or interior slashes are not\n // silently dropped, keeping a single canonical form per package name.\n const nameList = name.split('/');\n if (nameList.length === 1) {\n // normal package\n return validateName(nameList[0]);\n } else if (nameList.length === 2) {\n // scoped package\n return (\n nameList[0][0] === '@' && validateName(nameList[0].slice(1)) && validateName(nameList[1])\n );\n }\n // anything with 3+ segments is never a valid package name\n return false;\n}\n\n/**\n * Validate the package metadata, add additional properties whether are missing within\n * the metadata properties.\n * @param {*} manifest\n * @param {*} name\n * @return {Object} the object with additional properties as dist-tags ad versions\n */\nexport function normalizeMetadata(manifest: Manifest, name: string): Manifest {\n assert.strictEqual(manifest.name, name);\n const _manifest = { ...manifest };\n\n if (!isObject(manifest[DIST_TAGS])) {\n _manifest[DIST_TAGS] = {};\n }\n\n if (!Array.isArray(manifest[MAINTAINERS])) {\n _manifest[MAINTAINERS] = [];\n }\n\n // This may not be needed\n if (!isObject(manifest['versions'])) {\n _manifest['versions'] = {};\n }\n\n if (!isObject(manifest['time'])) {\n _manifest['time'] = {};\n }\n\n return _manifest;\n}\n\n/**\n * Check whether an element is an Object\n * @param {*} obj the element\n * @return {Boolean}\n */\nexport function isObject(obj: any): boolean {\n // if (obj === null || typeof obj === 'undefined' || typeof obj === 'string') {\n // return false;\n // }\n\n // return (\n // (typeof obj === 'object' || typeof obj.prototype === 'undefined') &&\n // Array.isArray(obj) === false\n // );\n return Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function validatePassword(\n password: string,\n validation: RegExp = DEFAULT_PASSWORD_VALIDATION\n): boolean {\n return typeof password === 'string' && validation instanceof RegExp\n ? password.match(validation) !== null\n : false;\n}\n\nexport function validateUserName(userName: any, expectedName: string): boolean {\n return (\n typeof userName === 'string' &&\n userName.split(':')[0] === 'org.couchdb.user' &&\n userName.split(':')[1] === expectedName\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AASA,SAAgB,oBAAoB,MAAuB;CACzD,OAAO,KAAK,WAAW,GAAG;AAC5B;;;;;;AAOA,SAAgB,aAAa,MAAuB;CAClD,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,IAAI,oBAAoB,IAAI,KAAK,KAAK,SAAS,GAAG,GAChD,OAAO,gBAAgB,IAAI;CAG7B,MAAM,iBAAyB,KAAK,YAAY;;;;;;;;;;;;CAahD,OAAO,EACL,CAAC,eAAe,MAAM,0BAA0B,KAChD,eAAe,WAAW,GAAG,KAC7B;EAAC;EAAgB;EAAa;CAAa,CAAC,CAAC,SAAS,cAAc;AAExE;;;;;AAMA,SAAgB,gBAAgB,MAAuB;CAGrD,MAAM,WAAW,KAAK,MAAM,GAAG;CAC/B,IAAI,SAAS,WAAW,GAEtB,OAAO,aAAa,SAAS,EAAE;MAC1B,IAAI,SAAS,WAAW,GAE7B,OACE,SAAS,EAAE,CAAC,OAAO,OAAO,aAAa,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,aAAa,SAAS,EAAE;CAI5F,OAAO;AACT;;;;;;;;AASA,SAAgB,kBAAkB,UAAoB,MAAwB;CAC5E,OAAO,YAAY,SAAS,MAAM,IAAI;CACtC,MAAM,YAAY,EAAE,GAAG,SAAS;CAEhC,IAAI,CAAC,SAAS,SAAA,YAAmB,GAC/B,UAAU,aAAa,CAAC;CAG1B,IAAI,CAAC,MAAM,QAAQ,SAAA,cAAqB,GACtC,UAAU,eAAe,CAAC;CAI5B,IAAI,CAAC,SAAS,SAAS,WAAW,GAChC,UAAU,cAAc,CAAC;CAG3B,IAAI,CAAC,SAAS,SAAS,OAAO,GAC5B,UAAU,UAAU,CAAC;CAGvB,OAAO;AACT;;;;;;AAOA,SAAgB,SAAS,KAAmB;CAS1C,OAAO,OAAO,UAAU,SAAS,KAAK,GAAG,MAAM;AACjD;AAEA,SAAgB,iBACd,UACA,aAAqB,6BACZ;CACT,OAAO,OAAO,aAAa,YAAY,sBAAsB,SACzD,SAAS,MAAM,UAAU,MAAM,OAC/B;AACN;AAEA,SAAgB,iBAAiB,UAAe,cAA+B;CAC7E,OACE,OAAO,aAAa,YACpB,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO,sBAC3B,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO;AAE/B"}
1
+ {"version":3,"file":"validation-utils.mjs","names":[],"sources":["../src/validation-utils.ts"],"sourcesContent":["import assert from 'node:assert';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport { DEFAULT_PASSWORD_VALIDATION, DIST_TAGS, MAINTAINERS } from './constants';\n\nexport { validatePublishSingleVersion } from './schemes/publish-manifest';\nexport { validateUnPublishSingleVersion } from './schemes/unpublish-manifest';\n\nconst scopedPackagePattern = /^(?:@([^/]+?)[/])?([^/]+?)$/;\nconst exclusionList = ['node_modules', 'favicon.ico'];\n\n// encodeURIComponent throws on malformed UTF-16, such as a lone surrogate\nfunction isUrlFriendly(value: string): boolean {\n try {\n return encodeURIComponent(value) === value;\n } catch {\n return false;\n }\n}\n\n/** Package name rules for existing packages; a leading hyphen stays valid. */\nexport function validatePackageName(name: unknown): boolean {\n if (typeof name !== 'string' || !name.length) {\n return false;\n }\n if (name.startsWith('.') || name.startsWith('_') || name.trim() !== name) {\n return false;\n }\n if (exclusionList.includes(name.toLowerCase())) {\n return false;\n }\n if (isUrlFriendly(name)) {\n return true;\n }\n const nameMatch = name.match(scopedPackagePattern);\n if (!nameMatch) {\n return false;\n }\n const [, user, pkg] = nameMatch;\n return user !== undefined && isUrlFriendly(user) && !pkg.startsWith('.') && isUrlFriendly(pkg);\n}\n\nexport function isPackageNameScoped(name: string): boolean {\n return name.startsWith('@');\n}\n\n/**\n * From normalize-package-data/lib/fixer.js\n * @param {*} name the package name\n * @return {Boolean} whether is valid or not\n */\nexport function validateName(name: string): boolean {\n if (typeof name !== 'string') {\n return false;\n }\n\n if (isPackageNameScoped(name) && name.includes('/')) {\n return validatePackage(name);\n }\n\n const normalizedName: string = name.toLowerCase();\n\n /**\n * Some context about the first regex\n * - npm used to have a different tarball naming system.\n * eg: http://registry.npmjs.com/thirty-two\n * https://registry.npmjs.org/thirty-two/-/thirty-two@0.0.1.tgz\n * The file name thirty-two@0.0.1.tgz, the version and the pkg name was separated by an at (@)\n * while nowadays the naming system is based in dashes\n * https://registry.npmjs.org/verdaccio/-/verdaccio-1.4.0.tgz\n *\n * more info here: https://github.com/rlidwka/sinopia/issues/75\n */\n return !(\n !normalizedName.match(/^[-a-zA-Z0-9_.!~*'()@]+$/) ||\n normalizedName.startsWith('.') || // \".bin\", etc.\n ['node_modules', '__proto__', 'favicon.ico'].includes(normalizedName)\n );\n}\n\n/**\n * Validate a package.\n * @return {Boolean} whether the package is valid or not\n */\nexport function validatePackage(name: string): boolean {\n if (!isValidPackagePath(name)) {\n return false;\n }\n return validatePackageName(name);\n}\n\nfunction isValidPackagePath(name: string): boolean {\n // Split on every separator (no limit) so trailing or interior slashes are not\n // silently dropped, keeping a single canonical form per package name.\n const nameList = name.split('/');\n if (nameList.length === 1) {\n // normal package\n return validateName(nameList[0]);\n } else if (nameList.length === 2) {\n // scoped package\n return (\n nameList[0][0] === '@' && validateName(nameList[0].slice(1)) && validateName(nameList[1])\n );\n }\n // anything with 3+ segments is never a valid package name\n return false;\n}\n\n/**\n * Validate the package metadata, add additional properties whether are missing within\n * the metadata properties.\n * @param {*} manifest\n * @param {*} name\n * @return {Object} the object with additional properties as dist-tags ad versions\n */\nexport function normalizeMetadata(manifest: Manifest, name: string): Manifest {\n assert.strictEqual(manifest.name, name);\n const _manifest = { ...manifest };\n\n if (!isObject(manifest[DIST_TAGS])) {\n _manifest[DIST_TAGS] = {};\n }\n\n if (!Array.isArray(manifest[MAINTAINERS])) {\n _manifest[MAINTAINERS] = [];\n }\n\n // This may not be needed\n if (!isObject(manifest['versions'])) {\n _manifest['versions'] = {};\n }\n\n if (!isObject(manifest['time'])) {\n _manifest['time'] = {};\n }\n\n return _manifest;\n}\n\n/**\n * Check whether an element is an Object\n * @param {*} obj the element\n * @return {Boolean}\n */\nexport function isObject(obj: any): boolean {\n // if (obj === null || typeof obj === 'undefined' || typeof obj === 'string') {\n // return false;\n // }\n\n // return (\n // (typeof obj === 'object' || typeof obj.prototype === 'undefined') &&\n // Array.isArray(obj) === false\n // );\n return Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function validatePassword(\n password: string,\n validation: RegExp = DEFAULT_PASSWORD_VALIDATION\n): boolean {\n return typeof password === 'string' && validation instanceof RegExp\n ? password.match(validation) !== null\n : false;\n}\n\nexport function validateUserName(userName: any, expectedName: string): boolean {\n return (\n typeof userName === 'string' &&\n userName.split(':')[0] === 'org.couchdb.user' &&\n userName.split(':')[1] === expectedName\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AASA,IAAM,uBAAuB;AAC7B,IAAM,gBAAgB,CAAC,gBAAgB,aAAa;AAGpD,SAAS,cAAc,OAAwB;CAC7C,IAAI;EACF,OAAO,mBAAmB,KAAK,MAAM;CACvC,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,SAAgB,oBAAoB,MAAwB;CAC1D,IAAI,OAAO,SAAS,YAAY,CAAC,KAAK,QACpC,OAAO;CAET,IAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,KAAK,MAAM,MAClE,OAAO;CAET,IAAI,cAAc,SAAS,KAAK,YAAY,CAAC,GAC3C,OAAO;CAET,IAAI,cAAc,IAAI,GACpB,OAAO;CAET,MAAM,YAAY,KAAK,MAAM,oBAAoB;CACjD,IAAI,CAAC,WACH,OAAO;CAET,MAAM,GAAG,MAAM,OAAO;CACtB,OAAO,SAAS,KAAA,KAAa,cAAc,IAAI,KAAK,CAAC,IAAI,WAAW,GAAG,KAAK,cAAc,GAAG;AAC/F;AAEA,SAAgB,oBAAoB,MAAuB;CACzD,OAAO,KAAK,WAAW,GAAG;AAC5B;;;;;;AAOA,SAAgB,aAAa,MAAuB;CAClD,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,IAAI,oBAAoB,IAAI,KAAK,KAAK,SAAS,GAAG,GAChD,OAAO,gBAAgB,IAAI;CAG7B,MAAM,iBAAyB,KAAK,YAAY;;;;;;;;;;;;CAahD,OAAO,EACL,CAAC,eAAe,MAAM,0BAA0B,KAChD,eAAe,WAAW,GAAG,KAC7B;EAAC;EAAgB;EAAa;CAAa,CAAC,CAAC,SAAS,cAAc;AAExE;;;;;AAMA,SAAgB,gBAAgB,MAAuB;CACrD,IAAI,CAAC,mBAAmB,IAAI,GAC1B,OAAO;CAET,OAAO,oBAAoB,IAAI;AACjC;AAEA,SAAS,mBAAmB,MAAuB;CAGjD,MAAM,WAAW,KAAK,MAAM,GAAG;CAC/B,IAAI,SAAS,WAAW,GAEtB,OAAO,aAAa,SAAS,EAAE;MAC1B,IAAI,SAAS,WAAW,GAE7B,OACE,SAAS,EAAE,CAAC,OAAO,OAAO,aAAa,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,aAAa,SAAS,EAAE;CAI5F,OAAO;AACT;;;;;;;;AASA,SAAgB,kBAAkB,UAAoB,MAAwB;CAC5E,OAAO,YAAY,SAAS,MAAM,IAAI;CACtC,MAAM,YAAY,EAAE,GAAG,SAAS;CAEhC,IAAI,CAAC,SAAS,SAAA,YAAmB,GAC/B,UAAU,aAAa,CAAC;CAG1B,IAAI,CAAC,MAAM,QAAQ,SAAA,cAAqB,GACtC,UAAU,eAAe,CAAC;CAI5B,IAAI,CAAC,SAAS,SAAS,WAAW,GAChC,UAAU,cAAc,CAAC;CAG3B,IAAI,CAAC,SAAS,SAAS,OAAO,GAC5B,UAAU,UAAU,CAAC;CAGvB,OAAO;AACT;;;;;;AAOA,SAAgB,SAAS,KAAmB;CAS1C,OAAO,OAAO,UAAU,SAAS,KAAK,GAAG,MAAM;AACjD;AAEA,SAAgB,iBACd,UACA,aAAqB,6BACZ;CACT,OAAO,OAAO,aAAa,YAAY,sBAAsB,SACzD,SAAS,MAAM,UAAU,MAAM,OAC/B;AACN;AAEA,SAAgB,iBAAiB,UAAe,cAA+B;CAC7E,OACE,OAAO,aAAa,YACpB,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO,sBAC3B,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO;AAE/B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/core",
3
- "version": "8.3.1",
3
+ "version": "8.3.2",
4
4
  "description": "Verdaccio Core Components",
5
5
  "keywords": [
6
6
  "enterprise",