@verdaccio/core 9.0.0-next-9.15 → 9.0.0-next-9.16
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/build/file-utils.d.ts +36 -0
- package/build/file-utils.js +60 -1
- package/build/file-utils.js.map +1 -1
- package/build/file-utils.mjs +59 -1
- package/build/file-utils.mjs.map +1 -1
- package/package.json +3 -2
package/build/file-utils.d.ts
CHANGED
|
@@ -14,3 +14,39 @@ export declare function createTempFolder(prefix: string): Promise<string>;
|
|
|
14
14
|
* @returns
|
|
15
15
|
*/
|
|
16
16
|
export declare function createTempStorageFolder(prefix: string, folder?: string): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a safe path within a base directory, preventing directory traversal attacks.
|
|
19
|
+
*
|
|
20
|
+
* This function provides security against path traversal by:
|
|
21
|
+
* - URL decoding the input path
|
|
22
|
+
* - Resolving the full absolute path
|
|
23
|
+
* - Checking that the resolved path stays within the base directory
|
|
24
|
+
* - Rejecting paths containing '..' that would escape the base directory
|
|
25
|
+
* - Rejecting absolute paths that bypass the base directory
|
|
26
|
+
*
|
|
27
|
+
* @param basePath The base directory that constrains file access
|
|
28
|
+
* @param requestPath The requested path from user input (may be URL-encoded)
|
|
29
|
+
* @returns The resolved safe absolute path or null if the path is unsafe/invalid
|
|
30
|
+
* @security Prevents directory traversal attacks by validating resolved paths
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveSafePath(basePath: string, requestPath?: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Sanitize a user-provided path while preserving directory separators.
|
|
35
|
+
*
|
|
36
|
+
* The web middleware uses this for `/-/assets/{*all}` which may include
|
|
37
|
+
* subfolders (e.g. `logos/verdaccio.svg`). We sanitize each path segment
|
|
38
|
+
* independently so `/` remains a real directory boundary.
|
|
39
|
+
*
|
|
40
|
+
* TODO: `sanitize-filename` silently rewrites segments instead of rejecting
|
|
41
|
+
* them (`file\0.txt` -> `file.txt`, `CON.svg` -> `.svg`, oversized segments
|
|
42
|
+
* truncated). Not exploitable today, but surprising; prefer 404 on destructive
|
|
43
|
+
* rewrite.
|
|
44
|
+
* TODO: `=== '..'` check is whitespace-strict — ` ..` / `.. ` slips past it.
|
|
45
|
+
* Use `path.normalize` before splitting, or `segment.trim() === '..'`.
|
|
46
|
+
* TODO: largely redundant with `resolveSafePath` on POSIX; the dep mainly earns
|
|
47
|
+
* its keep on Windows. Consider an inline `[<>:"|?*\0]` regex to drop the dep.
|
|
48
|
+
*
|
|
49
|
+
* @param filename The user-provided filename/path to sanitize.
|
|
50
|
+
* @returns The sanitized filename/path.
|
|
51
|
+
*/
|
|
52
|
+
export declare function sanitizeFilename(filename: string): string;
|
package/build/file-utils.js
CHANGED
|
@@ -4,11 +4,15 @@ let node_os = require("node:os");
|
|
|
4
4
|
node_os = require_runtime.__toESM(node_os);
|
|
5
5
|
let node_path = require("node:path");
|
|
6
6
|
node_path = require_runtime.__toESM(node_path);
|
|
7
|
+
let sanitize_filename = require("sanitize-filename");
|
|
8
|
+
sanitize_filename = require_runtime.__toESM(sanitize_filename);
|
|
7
9
|
//#region src/file-utils.ts
|
|
8
10
|
var file_utils_exports = /* @__PURE__ */ require_runtime.__exportAll({
|
|
9
11
|
Files: () => Files,
|
|
10
12
|
createTempFolder: () => createTempFolder,
|
|
11
|
-
createTempStorageFolder: () => createTempStorageFolder
|
|
13
|
+
createTempStorageFolder: () => createTempStorageFolder,
|
|
14
|
+
resolveSafePath: () => resolveSafePath,
|
|
15
|
+
sanitizeFilename: () => sanitizeFilename
|
|
12
16
|
});
|
|
13
17
|
var Files = { DatabaseName: ".verdaccio-db.json" };
|
|
14
18
|
/**
|
|
@@ -31,6 +35,61 @@ async function createTempStorageFolder(prefix, folder = "storage") {
|
|
|
31
35
|
await (0, node_fs_promises.mkdir)(storageFolder);
|
|
32
36
|
return storageFolder;
|
|
33
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a safe path within a base directory, preventing directory traversal attacks.
|
|
40
|
+
*
|
|
41
|
+
* This function provides security against path traversal by:
|
|
42
|
+
* - URL decoding the input path
|
|
43
|
+
* - Resolving the full absolute path
|
|
44
|
+
* - Checking that the resolved path stays within the base directory
|
|
45
|
+
* - Rejecting paths containing '..' that would escape the base directory
|
|
46
|
+
* - Rejecting absolute paths that bypass the base directory
|
|
47
|
+
*
|
|
48
|
+
* @param basePath The base directory that constrains file access
|
|
49
|
+
* @param requestPath The requested path from user input (may be URL-encoded)
|
|
50
|
+
* @returns The resolved safe absolute path or null if the path is unsafe/invalid
|
|
51
|
+
* @security Prevents directory traversal attacks by validating resolved paths
|
|
52
|
+
*/
|
|
53
|
+
function resolveSafePath(basePath, requestPath) {
|
|
54
|
+
try {
|
|
55
|
+
if (!requestPath || requestPath === "") return null;
|
|
56
|
+
const decoded = decodeURIComponent(requestPath);
|
|
57
|
+
if (node_path.default.isAbsolute(decoded)) return null;
|
|
58
|
+
const baseResolved = node_path.default.resolve(basePath);
|
|
59
|
+
const reqResolved = node_path.default.resolve(baseResolved, decoded);
|
|
60
|
+
const baseComparable = process.platform === "win32" ? baseResolved.toLowerCase() : baseResolved;
|
|
61
|
+
const reqComparable = process.platform === "win32" ? reqResolved.toLowerCase() : reqResolved;
|
|
62
|
+
if (reqComparable !== baseComparable && !reqComparable.startsWith(baseComparable + node_path.default.sep)) return null;
|
|
63
|
+
return reqResolved;
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Sanitize a user-provided path while preserving directory separators.
|
|
70
|
+
*
|
|
71
|
+
* The web middleware uses this for `/-/assets/{*all}` which may include
|
|
72
|
+
* subfolders (e.g. `logos/verdaccio.svg`). We sanitize each path segment
|
|
73
|
+
* independently so `/` remains a real directory boundary.
|
|
74
|
+
*
|
|
75
|
+
* TODO: `sanitize-filename` silently rewrites segments instead of rejecting
|
|
76
|
+
* them (`file\0.txt` -> `file.txt`, `CON.svg` -> `.svg`, oversized segments
|
|
77
|
+
* truncated). Not exploitable today, but surprising; prefer 404 on destructive
|
|
78
|
+
* rewrite.
|
|
79
|
+
* TODO: `=== '..'` check is whitespace-strict — ` ..` / `.. ` slips past it.
|
|
80
|
+
* Use `path.normalize` before splitting, or `segment.trim() === '..'`.
|
|
81
|
+
* TODO: largely redundant with `resolveSafePath` on POSIX; the dep mainly earns
|
|
82
|
+
* its keep on Windows. Consider an inline `[<>:"|?*\0]` regex to drop the dep.
|
|
83
|
+
*
|
|
84
|
+
* @param filename The user-provided filename/path to sanitize.
|
|
85
|
+
* @returns The sanitized filename/path.
|
|
86
|
+
*/
|
|
87
|
+
function sanitizeFilename(filename) {
|
|
88
|
+
return filename.replace(/\\/g, "/").split("/").map((segment) => {
|
|
89
|
+
if (segment === "." || segment === "..") return segment;
|
|
90
|
+
return (0, sanitize_filename.default)(segment);
|
|
91
|
+
}).join("/");
|
|
92
|
+
}
|
|
34
93
|
//#endregion
|
|
35
94
|
Object.defineProperty(exports, "file_utils_exports", {
|
|
36
95
|
enumerable: true,
|
package/build/file-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-utils.js","names":[],"sources":["../src/file-utils.ts"],"sourcesContent":["import { mkdir, mkdtemp } from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport const Files = {\n DatabaseName: '.verdaccio-db.json',\n};\n\n/**\n * Create a temporary folder.\n * @param prefix The prefix of the folder name.\n * @returns string\n */\nexport async function createTempFolder(prefix: string): Promise<string> {\n return await mkdtemp(path.join(os.tmpdir(), 'verdaccio-' + prefix + '-'));\n}\n\n/**\n * Create temporary folder for an asset.\n * @param prefix\n * @param folder name\n * @returns\n */\nexport async function createTempStorageFolder(prefix: string, folder = 'storage'): Promise<string> {\n const tempFolder = await createTempFolder(prefix);\n const storageFolder = path.join(tempFolder, folder);\n await mkdir(storageFolder);\n return storageFolder;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-utils.js","names":[],"sources":["../src/file-utils.ts"],"sourcesContent":["import { mkdir, mkdtemp } from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport sanitize from 'sanitize-filename';\n\nexport const Files = {\n DatabaseName: '.verdaccio-db.json',\n};\n\n/**\n * Create a temporary folder.\n * @param prefix The prefix of the folder name.\n * @returns string\n */\nexport async function createTempFolder(prefix: string): Promise<string> {\n return await mkdtemp(path.join(os.tmpdir(), 'verdaccio-' + prefix + '-'));\n}\n\n/**\n * Create temporary folder for an asset.\n * @param prefix\n * @param folder name\n * @returns\n */\nexport async function createTempStorageFolder(prefix: string, folder = 'storage'): Promise<string> {\n const tempFolder = await createTempFolder(prefix);\n const storageFolder = path.join(tempFolder, folder);\n await mkdir(storageFolder);\n return storageFolder;\n}\n\n/**\n * Resolve a safe path within a base directory, preventing directory traversal attacks.\n *\n * This function provides security against path traversal by:\n * - URL decoding the input path\n * - Resolving the full absolute path\n * - Checking that the resolved path stays within the base directory\n * - Rejecting paths containing '..' that would escape the base directory\n * - Rejecting absolute paths that bypass the base directory\n *\n * @param basePath The base directory that constrains file access\n * @param requestPath The requested path from user input (may be URL-encoded)\n * @returns The resolved safe absolute path or null if the path is unsafe/invalid\n * @security Prevents directory traversal attacks by validating resolved paths\n */\nexport function resolveSafePath(basePath: string, requestPath?: string): string | null {\n try {\n if (!requestPath || requestPath === '') {\n return null;\n }\n\n const decoded = decodeURIComponent(requestPath);\n // Prevent absolute paths (should not start from '/')\n if (path.isAbsolute(decoded)) {\n return null;\n }\n\n // Resolve against the base directory without requiring the target to exist.\n const baseResolved = path.resolve(basePath);\n const reqResolved = path.resolve(baseResolved, decoded);\n\n // Normalize for Windows case-insensitive filesystem comparisons.\n const baseComparable = process.platform === 'win32' ? baseResolved.toLowerCase() : baseResolved;\n const reqComparable = process.platform === 'win32' ? reqResolved.toLowerCase() : reqResolved;\n\n // Ensure the resolved path is within basePath (subdirectory or exactly the base).\n if (reqComparable !== baseComparable && !reqComparable.startsWith(baseComparable + path.sep)) {\n return null;\n }\n\n return reqResolved;\n } catch {\n // error resolving path (e.g., path does not exist or permission denied)\n return null;\n }\n}\n\n/**\n * Sanitize a user-provided path while preserving directory separators.\n *\n * The web middleware uses this for `/-/assets/{*all}` which may include\n * subfolders (e.g. `logos/verdaccio.svg`). We sanitize each path segment\n * independently so `/` remains a real directory boundary.\n *\n * TODO: `sanitize-filename` silently rewrites segments instead of rejecting\n * them (`file\\0.txt` -> `file.txt`, `CON.svg` -> `.svg`, oversized segments\n * truncated). Not exploitable today, but surprising; prefer 404 on destructive\n * rewrite.\n * TODO: `=== '..'` check is whitespace-strict — ` ..` / `.. ` slips past it.\n * Use `path.normalize` before splitting, or `segment.trim() === '..'`.\n * TODO: largely redundant with `resolveSafePath` on POSIX; the dep mainly earns\n * its keep on Windows. Consider an inline `[<>:\"|?*\\0]` regex to drop the dep.\n *\n * @param filename The user-provided filename/path to sanitize.\n * @returns The sanitized filename/path.\n */\nexport function sanitizeFilename(filename: string): string {\n // normalize windows path separator so the result is stable across platforms\n const normalized = filename.replace(/\\\\/g, '/');\n const segments = normalized.split('/').map((segment) => {\n // Keep traversal markers intact so `resolveSafePath()` can correctly\n // reject paths escaping the base directory.\n if (segment === '.' || segment === '..') {\n return segment;\n }\n return sanitize(segment);\n });\n return segments.join('/');\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAKA,IAAa,QAAQ,EACnB,cAAc,sBACf;;;;;;AAOD,eAAsB,iBAAiB,QAAiC;AACtE,QAAO,OAAA,GAAA,iBAAA,SAAc,UAAA,QAAK,KAAK,QAAA,QAAG,QAAQ,EAAE,eAAe,SAAS,IAAI,CAAC;;;;;;;;AAS3E,eAAsB,wBAAwB,QAAgB,SAAS,WAA4B;CACjG,MAAM,aAAa,MAAM,iBAAiB,OAAO;CACjD,MAAM,gBAAgB,UAAA,QAAK,KAAK,YAAY,OAAO;AACnD,QAAA,GAAA,iBAAA,OAAY,cAAc;AAC1B,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,gBAAgB,UAAkB,aAAqC;AACrF,KAAI;AACF,MAAI,CAAC,eAAe,gBAAgB,GAClC,QAAO;EAGT,MAAM,UAAU,mBAAmB,YAAY;AAE/C,MAAI,UAAA,QAAK,WAAW,QAAQ,CAC1B,QAAO;EAIT,MAAM,eAAe,UAAA,QAAK,QAAQ,SAAS;EAC3C,MAAM,cAAc,UAAA,QAAK,QAAQ,cAAc,QAAQ;EAGvD,MAAM,iBAAiB,QAAQ,aAAa,UAAU,aAAa,aAAa,GAAG;EACnF,MAAM,gBAAgB,QAAQ,aAAa,UAAU,YAAY,aAAa,GAAG;AAGjF,MAAI,kBAAkB,kBAAkB,CAAC,cAAc,WAAW,iBAAiB,UAAA,QAAK,IAAI,CAC1F,QAAO;AAGT,SAAO;SACD;AAEN,SAAO;;;;;;;;;;;;;;;;;;;;;;AAuBX,SAAgB,iBAAiB,UAA0B;AAWzD,QATmB,SAAS,QAAQ,OAAO,IAAI,CACnB,MAAM,IAAI,CAAC,KAAK,YAAY;AAGtD,MAAI,YAAY,OAAO,YAAY,KACjC,QAAO;AAET,UAAA,GAAA,kBAAA,SAAgB,QAAQ;GACxB,CACc,KAAK,IAAI"}
|
package/build/file-utils.mjs
CHANGED
|
@@ -2,11 +2,14 @@ import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
|
2
2
|
import { mkdir, mkdtemp } from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import sanitize from "sanitize-filename";
|
|
5
6
|
//#region src/file-utils.ts
|
|
6
7
|
var file_utils_exports = /* @__PURE__ */ __exportAll({
|
|
7
8
|
Files: () => Files,
|
|
8
9
|
createTempFolder: () => createTempFolder,
|
|
9
|
-
createTempStorageFolder: () => createTempStorageFolder
|
|
10
|
+
createTempStorageFolder: () => createTempStorageFolder,
|
|
11
|
+
resolveSafePath: () => resolveSafePath,
|
|
12
|
+
sanitizeFilename: () => sanitizeFilename
|
|
10
13
|
});
|
|
11
14
|
var Files = { DatabaseName: ".verdaccio-db.json" };
|
|
12
15
|
/**
|
|
@@ -29,6 +32,61 @@ async function createTempStorageFolder(prefix, folder = "storage") {
|
|
|
29
32
|
await mkdir(storageFolder);
|
|
30
33
|
return storageFolder;
|
|
31
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a safe path within a base directory, preventing directory traversal attacks.
|
|
37
|
+
*
|
|
38
|
+
* This function provides security against path traversal by:
|
|
39
|
+
* - URL decoding the input path
|
|
40
|
+
* - Resolving the full absolute path
|
|
41
|
+
* - Checking that the resolved path stays within the base directory
|
|
42
|
+
* - Rejecting paths containing '..' that would escape the base directory
|
|
43
|
+
* - Rejecting absolute paths that bypass the base directory
|
|
44
|
+
*
|
|
45
|
+
* @param basePath The base directory that constrains file access
|
|
46
|
+
* @param requestPath The requested path from user input (may be URL-encoded)
|
|
47
|
+
* @returns The resolved safe absolute path or null if the path is unsafe/invalid
|
|
48
|
+
* @security Prevents directory traversal attacks by validating resolved paths
|
|
49
|
+
*/
|
|
50
|
+
function resolveSafePath(basePath, requestPath) {
|
|
51
|
+
try {
|
|
52
|
+
if (!requestPath || requestPath === "") return null;
|
|
53
|
+
const decoded = decodeURIComponent(requestPath);
|
|
54
|
+
if (path.isAbsolute(decoded)) return null;
|
|
55
|
+
const baseResolved = path.resolve(basePath);
|
|
56
|
+
const reqResolved = path.resolve(baseResolved, decoded);
|
|
57
|
+
const baseComparable = process.platform === "win32" ? baseResolved.toLowerCase() : baseResolved;
|
|
58
|
+
const reqComparable = process.platform === "win32" ? reqResolved.toLowerCase() : reqResolved;
|
|
59
|
+
if (reqComparable !== baseComparable && !reqComparable.startsWith(baseComparable + path.sep)) return null;
|
|
60
|
+
return reqResolved;
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Sanitize a user-provided path while preserving directory separators.
|
|
67
|
+
*
|
|
68
|
+
* The web middleware uses this for `/-/assets/{*all}` which may include
|
|
69
|
+
* subfolders (e.g. `logos/verdaccio.svg`). We sanitize each path segment
|
|
70
|
+
* independently so `/` remains a real directory boundary.
|
|
71
|
+
*
|
|
72
|
+
* TODO: `sanitize-filename` silently rewrites segments instead of rejecting
|
|
73
|
+
* them (`file\0.txt` -> `file.txt`, `CON.svg` -> `.svg`, oversized segments
|
|
74
|
+
* truncated). Not exploitable today, but surprising; prefer 404 on destructive
|
|
75
|
+
* rewrite.
|
|
76
|
+
* TODO: `=== '..'` check is whitespace-strict — ` ..` / `.. ` slips past it.
|
|
77
|
+
* Use `path.normalize` before splitting, or `segment.trim() === '..'`.
|
|
78
|
+
* TODO: largely redundant with `resolveSafePath` on POSIX; the dep mainly earns
|
|
79
|
+
* its keep on Windows. Consider an inline `[<>:"|?*\0]` regex to drop the dep.
|
|
80
|
+
*
|
|
81
|
+
* @param filename The user-provided filename/path to sanitize.
|
|
82
|
+
* @returns The sanitized filename/path.
|
|
83
|
+
*/
|
|
84
|
+
function sanitizeFilename(filename) {
|
|
85
|
+
return filename.replace(/\\/g, "/").split("/").map((segment) => {
|
|
86
|
+
if (segment === "." || segment === "..") return segment;
|
|
87
|
+
return sanitize(segment);
|
|
88
|
+
}).join("/");
|
|
89
|
+
}
|
|
32
90
|
//#endregion
|
|
33
91
|
export { file_utils_exports };
|
|
34
92
|
|
package/build/file-utils.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-utils.mjs","names":[],"sources":["../src/file-utils.ts"],"sourcesContent":["import { mkdir, mkdtemp } from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport const Files = {\n DatabaseName: '.verdaccio-db.json',\n};\n\n/**\n * Create a temporary folder.\n * @param prefix The prefix of the folder name.\n * @returns string\n */\nexport async function createTempFolder(prefix: string): Promise<string> {\n return await mkdtemp(path.join(os.tmpdir(), 'verdaccio-' + prefix + '-'));\n}\n\n/**\n * Create temporary folder for an asset.\n * @param prefix\n * @param folder name\n * @returns\n */\nexport async function createTempStorageFolder(prefix: string, folder = 'storage'): Promise<string> {\n const tempFolder = await createTempFolder(prefix);\n const storageFolder = path.join(tempFolder, folder);\n await mkdir(storageFolder);\n return storageFolder;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-utils.mjs","names":[],"sources":["../src/file-utils.ts"],"sourcesContent":["import { mkdir, mkdtemp } from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport sanitize from 'sanitize-filename';\n\nexport const Files = {\n DatabaseName: '.verdaccio-db.json',\n};\n\n/**\n * Create a temporary folder.\n * @param prefix The prefix of the folder name.\n * @returns string\n */\nexport async function createTempFolder(prefix: string): Promise<string> {\n return await mkdtemp(path.join(os.tmpdir(), 'verdaccio-' + prefix + '-'));\n}\n\n/**\n * Create temporary folder for an asset.\n * @param prefix\n * @param folder name\n * @returns\n */\nexport async function createTempStorageFolder(prefix: string, folder = 'storage'): Promise<string> {\n const tempFolder = await createTempFolder(prefix);\n const storageFolder = path.join(tempFolder, folder);\n await mkdir(storageFolder);\n return storageFolder;\n}\n\n/**\n * Resolve a safe path within a base directory, preventing directory traversal attacks.\n *\n * This function provides security against path traversal by:\n * - URL decoding the input path\n * - Resolving the full absolute path\n * - Checking that the resolved path stays within the base directory\n * - Rejecting paths containing '..' that would escape the base directory\n * - Rejecting absolute paths that bypass the base directory\n *\n * @param basePath The base directory that constrains file access\n * @param requestPath The requested path from user input (may be URL-encoded)\n * @returns The resolved safe absolute path or null if the path is unsafe/invalid\n * @security Prevents directory traversal attacks by validating resolved paths\n */\nexport function resolveSafePath(basePath: string, requestPath?: string): string | null {\n try {\n if (!requestPath || requestPath === '') {\n return null;\n }\n\n const decoded = decodeURIComponent(requestPath);\n // Prevent absolute paths (should not start from '/')\n if (path.isAbsolute(decoded)) {\n return null;\n }\n\n // Resolve against the base directory without requiring the target to exist.\n const baseResolved = path.resolve(basePath);\n const reqResolved = path.resolve(baseResolved, decoded);\n\n // Normalize for Windows case-insensitive filesystem comparisons.\n const baseComparable = process.platform === 'win32' ? baseResolved.toLowerCase() : baseResolved;\n const reqComparable = process.platform === 'win32' ? reqResolved.toLowerCase() : reqResolved;\n\n // Ensure the resolved path is within basePath (subdirectory or exactly the base).\n if (reqComparable !== baseComparable && !reqComparable.startsWith(baseComparable + path.sep)) {\n return null;\n }\n\n return reqResolved;\n } catch {\n // error resolving path (e.g., path does not exist or permission denied)\n return null;\n }\n}\n\n/**\n * Sanitize a user-provided path while preserving directory separators.\n *\n * The web middleware uses this for `/-/assets/{*all}` which may include\n * subfolders (e.g. `logos/verdaccio.svg`). We sanitize each path segment\n * independently so `/` remains a real directory boundary.\n *\n * TODO: `sanitize-filename` silently rewrites segments instead of rejecting\n * them (`file\\0.txt` -> `file.txt`, `CON.svg` -> `.svg`, oversized segments\n * truncated). Not exploitable today, but surprising; prefer 404 on destructive\n * rewrite.\n * TODO: `=== '..'` check is whitespace-strict — ` ..` / `.. ` slips past it.\n * Use `path.normalize` before splitting, or `segment.trim() === '..'`.\n * TODO: largely redundant with `resolveSafePath` on POSIX; the dep mainly earns\n * its keep on Windows. Consider an inline `[<>:\"|?*\\0]` regex to drop the dep.\n *\n * @param filename The user-provided filename/path to sanitize.\n * @returns The sanitized filename/path.\n */\nexport function sanitizeFilename(filename: string): string {\n // normalize windows path separator so the result is stable across platforms\n const normalized = filename.replace(/\\\\/g, '/');\n const segments = normalized.split('/').map((segment) => {\n // Keep traversal markers intact so `resolveSafePath()` can correctly\n // reject paths escaping the base directory.\n if (segment === '.' || segment === '..') {\n return segment;\n }\n return sanitize(segment);\n });\n return segments.join('/');\n}\n"],"mappings":";;;;;;;;;;;;;AAKA,IAAa,QAAQ,EACnB,cAAc,sBACf;;;;;;AAOD,eAAsB,iBAAiB,QAAiC;AACtE,QAAO,MAAM,QAAQ,KAAK,KAAK,GAAG,QAAQ,EAAE,eAAe,SAAS,IAAI,CAAC;;;;;;;;AAS3E,eAAsB,wBAAwB,QAAgB,SAAS,WAA4B;CACjG,MAAM,aAAa,MAAM,iBAAiB,OAAO;CACjD,MAAM,gBAAgB,KAAK,KAAK,YAAY,OAAO;AACnD,OAAM,MAAM,cAAc;AAC1B,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,gBAAgB,UAAkB,aAAqC;AACrF,KAAI;AACF,MAAI,CAAC,eAAe,gBAAgB,GAClC,QAAO;EAGT,MAAM,UAAU,mBAAmB,YAAY;AAE/C,MAAI,KAAK,WAAW,QAAQ,CAC1B,QAAO;EAIT,MAAM,eAAe,KAAK,QAAQ,SAAS;EAC3C,MAAM,cAAc,KAAK,QAAQ,cAAc,QAAQ;EAGvD,MAAM,iBAAiB,QAAQ,aAAa,UAAU,aAAa,aAAa,GAAG;EACnF,MAAM,gBAAgB,QAAQ,aAAa,UAAU,YAAY,aAAa,GAAG;AAGjF,MAAI,kBAAkB,kBAAkB,CAAC,cAAc,WAAW,iBAAiB,KAAK,IAAI,CAC1F,QAAO;AAGT,SAAO;SACD;AAEN,SAAO;;;;;;;;;;;;;;;;;;;;;;AAuBX,SAAgB,iBAAiB,UAA0B;AAWzD,QATmB,SAAS,QAAQ,OAAO,IAAI,CACnB,MAAM,IAAI,CAAC,KAAK,YAAY;AAGtD,MAAI,YAAY,OAAO,YAAY,KACjC,QAAO;AAET,SAAO,SAAS,QAAQ;GACxB,CACc,KAAK,IAAI"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/core",
|
|
3
|
-
"version": "9.0.0-next-9.
|
|
3
|
+
"version": "9.0.0-next-9.16",
|
|
4
4
|
"description": "Verdaccio Core Components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"private",
|
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
"http-status-codes": "2.3.0",
|
|
39
39
|
"minimatch": "9.0.7",
|
|
40
40
|
"process-warning": "5.0.0",
|
|
41
|
+
"sanitize-filename": "1.6.3",
|
|
41
42
|
"semver": "7.7.4"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
|
-
"@verdaccio/types": "14.0.0-next-9.
|
|
45
|
+
"@verdaccio/types": "14.0.0-next-9.7",
|
|
45
46
|
"express": "5.2.1",
|
|
46
47
|
"typedoc": "0.28.14",
|
|
47
48
|
"vitest": "4.1.0"
|