@verdaccio/core 8.3.1 → 8.3.3
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
|
|
@@ -27,5 +29,5 @@ export declare function normalizeMetadata(manifest: Manifest, name: string): Man
|
|
|
27
29
|
* @return {Boolean}
|
|
28
30
|
*/
|
|
29
31
|
export declare function isObject(obj: any): boolean;
|
|
30
|
-
export declare function validatePassword(password:
|
|
32
|
+
export declare function validatePassword(password: unknown, validation?: RegExp): boolean;
|
|
31
33
|
export declare function validateUserName(userName: any, expectedName: string): boolean;
|
|
@@ -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:
|
|
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: unknown,\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:
|
|
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: unknown,\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"}
|