@openclaw/fs-safe 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +4 -2
- package/dist/advanced.d.ts +1 -1
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +1 -1
- package/dist/archive-entry.d.ts.map +1 -1
- package/dist/archive-entry.js +4 -3
- package/dist/archive-gzip-tail.d.ts.map +1 -1
- package/dist/archive-gzip-tail.js +13 -9
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +37 -33
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +17 -5
- package/dist/bounded-read.js +2 -2
- package/dist/device-path.d.ts.map +1 -1
- package/dist/device-path.js +5 -3
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +9 -2
- package/dist/file-store-prune.d.ts.map +1 -1
- package/dist/file-store-prune.js +9 -1
- package/dist/filename.d.ts +1 -0
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +30 -13
- package/dist/guarded-mkdir.d.ts +2 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +50 -15
- package/dist/guest.d.ts.map +1 -1
- package/dist/guest.js +12 -4
- package/dist/install-path.d.ts +6 -0
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +13 -0
- package/dist/json-durable-queue-ownership.d.ts +2 -0
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +47 -3
- package/dist/json-durable-queue-read.d.ts +6 -0
- package/dist/json-durable-queue-read.d.ts.map +1 -0
- package/dist/json-durable-queue-read.js +59 -0
- package/dist/json-durable-queue.d.ts +1 -1
- package/dist/json-durable-queue.d.ts.map +1 -1
- package/dist/json-durable-queue.js +37 -80
- package/dist/native-binding.d.ts +7 -0
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/path-scope-lexical.d.ts +14 -0
- package/dist/path-scope-lexical.d.ts.map +1 -0
- package/dist/path-scope-lexical.js +27 -0
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +20 -2
- package/dist/pinned-write.js +1 -0
- package/dist/root-boundary.d.ts +25 -0
- package/dist/root-boundary.d.ts.map +1 -0
- package/dist/root-boundary.js +177 -0
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +32 -5
- package/dist/root-directory-list.d.ts.map +1 -1
- package/dist/root-directory-list.js +10 -2
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +53 -34
- package/dist/root-move-preflight.d.ts +8 -0
- package/dist/root-move-preflight.d.ts.map +1 -0
- package/dist/root-move-preflight.js +16 -0
- package/dist/root-path-existing.d.ts +2 -0
- package/dist/root-path-existing.d.ts.map +1 -1
- package/dist/root-path-existing.js +10 -2
- package/dist/root-path.d.ts +2 -0
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +54 -26
- package/dist/root-paths.d.ts +2 -6
- package/dist/root-paths.d.ts.map +1 -1
- package/dist/root-paths.js +14 -26
- package/dist/root-walk.d.ts.map +1 -1
- package/dist/root-walk.js +2 -1
- package/dist/root-write-mode.d.ts +2 -0
- package/dist/root-write-mode.d.ts.map +1 -1
- package/dist/root-write-mode.js +20 -7
- package/dist/root-write-verification.d.ts.map +1 -1
- package/dist/root-write-verification.js +12 -3
- package/dist/safe-path-segment.d.ts.map +1 -1
- package/dist/safe-path-segment.js +3 -1
- package/dist/secure-file-windows.d.ts +10 -0
- package/dist/secure-file-windows.d.ts.map +1 -0
- package/dist/secure-file-windows.js +186 -0
- package/dist/secure-file.d.ts.map +1 -1
- package/dist/secure-file.js +6 -3
- package/dist/sibling-staged-file.d.ts +1 -0
- package/dist/sibling-staged-file.d.ts.map +1 -1
- package/dist/sibling-staged-file.js +7 -0
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +2 -1
- package/dist/sidecar-lock-acquire.js +1 -1
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +2 -3
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +3 -1
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +11 -10
- package/docs/advanced.md +3 -1
- package/docs/archive.md +6 -0
- package/docs/contributing.md +4 -1
- package/docs/copy.md +1 -1
- package/docs/durability.md +4 -2
- package/docs/file-store.md +6 -0
- package/docs/filename.md +9 -2
- package/docs/guest.md +5 -0
- package/docs/install-path.md +59 -13
- package/docs/install.md +4 -1
- package/docs/native-helper.md +4 -2
- package/docs/native.md +14 -2
- package/docs/path.md +1 -1
- package/docs/permissions.md +26 -1
- package/docs/public-api.md +5 -0
- package/docs/root.md +3 -1
- package/docs/secure-file.md +15 -14
- package/docs/security-model.md +1 -1
- package/docs/store.md +22 -1
- package/docs/temp.md +4 -0
- package/package.json +8 -8
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { isPathInside, isPathRelativeEscape } from "./path.js";
|
|
3
|
+
function pathStaysWithinRoot(rootDir, candidatePath) {
|
|
4
|
+
if (process.platform !== "win32") {
|
|
5
|
+
return candidatePath !== rootDir && isPathInside(rootDir, candidatePath);
|
|
6
|
+
}
|
|
7
|
+
const relative = path.relative(rootDir, candidatePath);
|
|
8
|
+
return Boolean(relative) && !isPathRelativeEscape(relative);
|
|
9
|
+
}
|
|
10
|
+
export function resolvePathWithinNormalizedRoot(params, root) {
|
|
11
|
+
const raw = params.requestedPath.trim();
|
|
12
|
+
if (!raw) {
|
|
13
|
+
if (!params.defaultFileName) {
|
|
14
|
+
return { ok: false, error: "path is required" };
|
|
15
|
+
}
|
|
16
|
+
const defaultPath = path.resolve(root, params.defaultFileName);
|
|
17
|
+
if (!pathStaysWithinRoot(root, defaultPath)) {
|
|
18
|
+
return { ok: false, error: `Invalid path: must stay within ${params.scopeLabel}` };
|
|
19
|
+
}
|
|
20
|
+
return { ok: true, path: defaultPath };
|
|
21
|
+
}
|
|
22
|
+
const resolved = path.resolve(root, raw);
|
|
23
|
+
if (!pathStaysWithinRoot(root, resolved)) {
|
|
24
|
+
return { ok: false, error: `Invalid path: must stay within ${params.scopeLabel}` };
|
|
25
|
+
}
|
|
26
|
+
return { ok: true, path: resolved };
|
|
27
|
+
}
|
package/dist/path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAOzB,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,GAChC,MAAM,kBAAkB,CAAC;AAM1B,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWvE;
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAOzB,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,GAChC,MAAM,kBAAkB,CAAC;AAM1B,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWvE;AAWD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAI1E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,SAA6B,GAAG,IAAI,CAIjG;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE3D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CA0ClE;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAa/F;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChE,OAAO,CAUT;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG,IAAI,CAMhE;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BpE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAOrF"}
|
package/dist/path.js
CHANGED
|
@@ -19,6 +19,14 @@ export function normalizeWindowsPathForComparison(input) {
|
|
|
19
19
|
// whitespace is part of the path and must not be trimmed away.
|
|
20
20
|
return normalized.replaceAll("/", "\\").toLowerCase();
|
|
21
21
|
}
|
|
22
|
+
function resolveWindowsPathForComparison(input) {
|
|
23
|
+
const resolved = path.win32.resolve(input);
|
|
24
|
+
// Ordinary drive paths are already normalized by resolve. Namespace paths
|
|
25
|
+
// retain Node's additional normalization rules before comparison.
|
|
26
|
+
return resolved[1] === ":" && path.win32.isAbsolute(resolved)
|
|
27
|
+
? resolved.toLowerCase()
|
|
28
|
+
: normalizeWindowsPathForComparison(resolved);
|
|
29
|
+
}
|
|
22
30
|
export function isNodeError(value) {
|
|
23
31
|
return Boolean(value && typeof value === "object" && "code" in value);
|
|
24
32
|
}
|
|
@@ -38,8 +46,18 @@ export function isSymlinkOpenError(value) {
|
|
|
38
46
|
}
|
|
39
47
|
export function isPathInside(root, target) {
|
|
40
48
|
if (process.platform === "win32") {
|
|
41
|
-
const rootForCompare =
|
|
42
|
-
const targetForCompare =
|
|
49
|
+
const rootForCompare = resolveWindowsPathForComparison(root);
|
|
50
|
+
const targetForCompare = resolveWindowsPathForComparison(target);
|
|
51
|
+
// Resolved drive paths already have canonical separators and case. A full
|
|
52
|
+
// segment prefix needs no second resolution through path.relative.
|
|
53
|
+
// Colon-bearing components keep Node's relative-path interpretation.
|
|
54
|
+
if (rootForCompare[1] === ":" && path.win32.isAbsolute(rootForCompare) &&
|
|
55
|
+
!targetForCompare.includes(":", 2) &&
|
|
56
|
+
(targetForCompare === rootForCompare ||
|
|
57
|
+
(targetForCompare.startsWith(rootForCompare) &&
|
|
58
|
+
(rootForCompare.endsWith("\\") || targetForCompare[rootForCompare.length] === "\\")))) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
43
61
|
const relative = path.win32.relative(rootForCompare, targetForCompare);
|
|
44
62
|
const firstSegment = relative.split(path.win32.sep)[0];
|
|
45
63
|
return (relative === "" || (firstSegment !== ".." && !path.win32.isAbsolute(relative)));
|
package/dist/pinned-write.js
CHANGED
|
@@ -103,6 +103,7 @@ async function runPinnedWriteFallback(params) {
|
|
|
103
103
|
parentPath = await mkdirPathComponentsWithGuards({
|
|
104
104
|
rootReal: params.rootPath,
|
|
105
105
|
targetPath: parentPath,
|
|
106
|
+
rootIdentity: params.rootIdentity,
|
|
106
107
|
assertBeforeMutation: params.assertBeforeMutation,
|
|
107
108
|
beforeComponent: async (componentPath) => await getFsSafeTestHooks()?.beforeRootFallbackMutation?.("mkdir", componentPath),
|
|
108
109
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type RootBoundaryIdentity = Readonly<{
|
|
2
|
+
dev: number | bigint;
|
|
3
|
+
ino: number | bigint;
|
|
4
|
+
}>;
|
|
5
|
+
export type AdmittedRootPath = Readonly<{
|
|
6
|
+
path: string;
|
|
7
|
+
relativePath: string;
|
|
8
|
+
admission: "exact" | "identity";
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Admit a path at a trusted directory boundary.
|
|
12
|
+
*
|
|
13
|
+
* On Windows, an exact structural prefix is allocation-only and performs no
|
|
14
|
+
* filesystem observation. A match which depends on case folding is accepted
|
|
15
|
+
* only when the candidate prefix names the exact trusted root object. Accepted
|
|
16
|
+
* paths are always returned under the trusted root spelling.
|
|
17
|
+
*/
|
|
18
|
+
export declare function admitPathInsideRoot(params: {
|
|
19
|
+
rootPath: string;
|
|
20
|
+
candidatePath: string;
|
|
21
|
+
rootIdentity?: RootBoundaryIdentity;
|
|
22
|
+
resolveCandidateRoot?: boolean;
|
|
23
|
+
identityCache?: Map<string, boolean>;
|
|
24
|
+
}): AdmittedRootPath | undefined;
|
|
25
|
+
//# sourceMappingURL=root-boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-boundary.d.ts","sourceRoot":"","sources":["../src/root-boundary.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,GAAG,UAAU,CAAC;CACjC,CAAC,CAAC;AAwHH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,GAAG,gBAAgB,GAAG,SAAS,CA6D/B"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { inspectDirectoryIdentitySync } from "./directory-guard.js";
|
|
3
|
+
import { isPathRelativeEscape } from "./path.js";
|
|
4
|
+
import { realpathSync } from "./realpath.js";
|
|
5
|
+
function windowsComparablePath(value, normalize) {
|
|
6
|
+
const original = normalize
|
|
7
|
+
? path.win32.normalize(value.replaceAll("/", "\\"))
|
|
8
|
+
: value.replaceAll("/", "\\");
|
|
9
|
+
if (/^\\\\\?\\UNC\\/i.test(original)) {
|
|
10
|
+
return {
|
|
11
|
+
original,
|
|
12
|
+
comparison: `\\\\${original.slice(8)}`,
|
|
13
|
+
originalIndex: (comparisonIndex) => comparisonIndex + 6,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (original.startsWith("\\\\?\\")) {
|
|
17
|
+
return {
|
|
18
|
+
original,
|
|
19
|
+
comparison: original.slice(4),
|
|
20
|
+
originalIndex: (comparisonIndex) => comparisonIndex + 4,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return { original, comparison: original, originalIndex: (comparisonIndex) => comparisonIndex };
|
|
24
|
+
}
|
|
25
|
+
function trimWindowsTrailingSeparators(value) {
|
|
26
|
+
const rootLength = path.win32.parse(value).root.length;
|
|
27
|
+
let end = value.length;
|
|
28
|
+
while (end > rootLength && value[end - 1] === "\\")
|
|
29
|
+
end -= 1;
|
|
30
|
+
return value.slice(0, end);
|
|
31
|
+
}
|
|
32
|
+
function trimWindowsLeadingSeparators(value) {
|
|
33
|
+
let start = 0;
|
|
34
|
+
while (value[start] === "\\")
|
|
35
|
+
start += 1;
|
|
36
|
+
return value.slice(start);
|
|
37
|
+
}
|
|
38
|
+
function exactWindowsRootPrefix(rootPath, candidatePath) {
|
|
39
|
+
const root = trimWindowsTrailingSeparators(rootPath.replaceAll("/", "\\"));
|
|
40
|
+
const candidate = candidatePath.replaceAll("/", "\\");
|
|
41
|
+
let relativePath;
|
|
42
|
+
if (candidate === root) {
|
|
43
|
+
relativePath = "";
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const rootWithSep = root.endsWith("\\") ? root : `${root}\\`;
|
|
47
|
+
if (!candidate.startsWith(rootWithSep))
|
|
48
|
+
return undefined;
|
|
49
|
+
relativePath = trimWindowsLeadingSeparators(candidate.slice(rootWithSep.length));
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
admission: "exact",
|
|
53
|
+
candidateRootPath: root,
|
|
54
|
+
path: relativePath === "" ? root : `${root}${root.endsWith("\\") ? "" : "\\"}${relativePath}`,
|
|
55
|
+
relativePath,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function windowsRootPrefix(rootPath, candidatePath) {
|
|
59
|
+
const exact = exactWindowsRootPrefix(rootPath, candidatePath);
|
|
60
|
+
if (exact)
|
|
61
|
+
return exact;
|
|
62
|
+
const trusted = windowsComparablePath(rootPath, true);
|
|
63
|
+
const supplied = windowsComparablePath(candidatePath, false);
|
|
64
|
+
const root = trimWindowsTrailingSeparators(trusted.original);
|
|
65
|
+
const rootComparison = trimWindowsTrailingSeparators(trusted.comparison);
|
|
66
|
+
const candidate = supplied.comparison;
|
|
67
|
+
if (!path.win32.isAbsolute(supplied.original))
|
|
68
|
+
return undefined;
|
|
69
|
+
let relativePath;
|
|
70
|
+
let candidateRootPath;
|
|
71
|
+
let admission;
|
|
72
|
+
if (candidate === rootComparison) {
|
|
73
|
+
relativePath = "";
|
|
74
|
+
candidateRootPath = supplied.original;
|
|
75
|
+
admission = "exact";
|
|
76
|
+
}
|
|
77
|
+
else if (candidate.toLowerCase() === rootComparison.toLowerCase()) {
|
|
78
|
+
relativePath = "";
|
|
79
|
+
candidateRootPath = supplied.original;
|
|
80
|
+
admission = "identity";
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const rootWithSep = rootComparison.endsWith("\\") ? rootComparison : `${rootComparison}\\`;
|
|
84
|
+
const candidatePrefix = candidate.slice(0, rootWithSep.length);
|
|
85
|
+
if (candidatePrefix === rootWithSep) {
|
|
86
|
+
admission = "exact";
|
|
87
|
+
}
|
|
88
|
+
else if (candidatePrefix.toLowerCase() === rootWithSep.toLowerCase()) {
|
|
89
|
+
admission = "identity";
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
relativePath = trimWindowsLeadingSeparators(candidate.slice(rootWithSep.length));
|
|
95
|
+
candidateRootPath = supplied.original.slice(0, supplied.originalIndex(rootComparison.length));
|
|
96
|
+
}
|
|
97
|
+
const rebasedPath = relativePath === ""
|
|
98
|
+
? root
|
|
99
|
+
: `${root}${root.endsWith("\\") ? "" : "\\"}${relativePath}`;
|
|
100
|
+
return { candidateRootPath, path: rebasedPath, relativePath, admission };
|
|
101
|
+
}
|
|
102
|
+
function exactRootIdentity(rootPath, expected) {
|
|
103
|
+
if (typeof expected?.dev === "bigint" && typeof expected.ino === "bigint") {
|
|
104
|
+
return { dev: expected.dev, ino: expected.ino };
|
|
105
|
+
}
|
|
106
|
+
const observed = inspectDirectoryIdentitySync(rootPath);
|
|
107
|
+
return { dev: observed.dev, ino: observed.ino };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Admit a path at a trusted directory boundary.
|
|
111
|
+
*
|
|
112
|
+
* On Windows, an exact structural prefix is allocation-only and performs no
|
|
113
|
+
* filesystem observation. A match which depends on case folding is accepted
|
|
114
|
+
* only when the candidate prefix names the exact trusted root object. Accepted
|
|
115
|
+
* paths are always returned under the trusted root spelling.
|
|
116
|
+
*/
|
|
117
|
+
export function admitPathInsideRoot(params) {
|
|
118
|
+
// Some platform-fallback tests intentionally spoof process.platform while
|
|
119
|
+
// retaining Node's POSIX path module. A single-slash absolute root remains
|
|
120
|
+
// unambiguously POSIX; double-slash and slash-backslash roots are reserved
|
|
121
|
+
// for the synthetic Windows namespace cases below.
|
|
122
|
+
const usesPosixBoundary = process.platform !== "win32" || (path.sep === "/" &&
|
|
123
|
+
params.rootPath.startsWith("/") &&
|
|
124
|
+
params.rootPath[1] !== "/" &&
|
|
125
|
+
params.rootPath[1] !== "\\");
|
|
126
|
+
if (usesPosixBoundary) {
|
|
127
|
+
if (params.rootPath.startsWith("/") &&
|
|
128
|
+
params.candidatePath.startsWith("/") &&
|
|
129
|
+
!params.candidatePath.includes("/..") &&
|
|
130
|
+
(params.candidatePath === params.rootPath ||
|
|
131
|
+
(params.candidatePath.startsWith(params.rootPath) &&
|
|
132
|
+
(params.rootPath.endsWith("/") || params.candidatePath[params.rootPath.length] === "/")))) {
|
|
133
|
+
const relativeStart = params.rootPath.endsWith("/")
|
|
134
|
+
? params.rootPath.length
|
|
135
|
+
: params.rootPath.length + 1;
|
|
136
|
+
return {
|
|
137
|
+
admission: "exact",
|
|
138
|
+
path: params.candidatePath,
|
|
139
|
+
relativePath: params.candidatePath === params.rootPath
|
|
140
|
+
? ""
|
|
141
|
+
: params.candidatePath.slice(relativeStart),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const root = path.resolve(params.rootPath);
|
|
145
|
+
const candidate = path.resolve(params.candidatePath);
|
|
146
|
+
const relativePath = path.relative(root, candidate);
|
|
147
|
+
if (isPathRelativeEscape(relativePath))
|
|
148
|
+
return undefined;
|
|
149
|
+
return { path: candidate, relativePath: relativePath === "." ? "" : relativePath, admission: "exact" };
|
|
150
|
+
}
|
|
151
|
+
const match = windowsRootPrefix(params.rootPath, params.candidatePath);
|
|
152
|
+
if (!match)
|
|
153
|
+
return undefined;
|
|
154
|
+
const admitted = () => ({
|
|
155
|
+
admission: match.admission,
|
|
156
|
+
path: match.path,
|
|
157
|
+
relativePath: match.relativePath,
|
|
158
|
+
});
|
|
159
|
+
if (match.admission === "exact")
|
|
160
|
+
return admitted();
|
|
161
|
+
const cached = params.identityCache?.get(match.candidateRootPath);
|
|
162
|
+
if (cached !== undefined)
|
|
163
|
+
return cached ? admitted() : undefined;
|
|
164
|
+
try {
|
|
165
|
+
const expected = exactRootIdentity(params.rootPath, params.rootIdentity);
|
|
166
|
+
const candidateRootPath = params.resolveCandidateRoot
|
|
167
|
+
? realpathSync.native(match.candidateRootPath)
|
|
168
|
+
: match.candidateRootPath;
|
|
169
|
+
inspectDirectoryIdentitySync(candidateRootPath, expected);
|
|
170
|
+
params.identityCache?.set(match.candidateRootPath, true);
|
|
171
|
+
return admitted();
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
params.identityCache?.set(match.candidateRootPath, false);
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-context.d.ts","sourceRoot":"","sources":["../src/root-context.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"root-context.d.ts","sourceRoot":"","sources":["../src/root-context.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAW,MAAM,WACM,CAAC;AAEtD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAEtE;AAED,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAKzE;AAMD,wBAAsB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAetF;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA4B9E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAyBhF;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhF;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IACR,cAAc,CAAC,EAAE,mBAAmB,GAAG,YAAY,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC,GACA,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAoEtE;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEvE"}
|
package/dist/root-context.js
CHANGED
|
@@ -6,6 +6,7 @@ import { FsSafeError } from "./errors.js";
|
|
|
6
6
|
import { sameFileIdentity } from "./file-identity.js";
|
|
7
7
|
import { assertNoNulPathInput, assertNoUnsafeDeviceReadPath, hasNodeErrorCode, isNotFoundPathError, isPathInside, } from "./path.js";
|
|
8
8
|
import { ROOT_PATH_ALIAS_POLICIES, resolveRootPath } from "./root-path.js";
|
|
9
|
+
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
9
10
|
import { outsideWorkspaceError, rootPathChangedError } from "./root-errors.js";
|
|
10
11
|
import { isDriveRelativePath } from "./safe-path-segment.js";
|
|
11
12
|
import { realpathSync } from "./realpath.js";
|
|
@@ -77,11 +78,21 @@ export function rootRelativeReadPath(root, filePath) {
|
|
|
77
78
|
if (!absoluteInput)
|
|
78
79
|
return filePath;
|
|
79
80
|
const raw = process.platform === "win32" ? filePath.replaceAll("/", path.sep) : filePath;
|
|
80
|
-
|
|
81
|
+
const bases = root.rootDir === root.rootReal ? [root.rootReal] : [root.rootDir, root.rootReal];
|
|
82
|
+
for (const base of bases) {
|
|
83
|
+
if (process.platform === "win32") {
|
|
84
|
+
const admitted = admitPathInsideRoot({
|
|
85
|
+
rootPath: base,
|
|
86
|
+
candidatePath: raw,
|
|
87
|
+
rootIdentity: root.rootIdentity,
|
|
88
|
+
resolveCandidateRoot: base === root.rootDir && root.rootDir !== root.rootReal,
|
|
89
|
+
});
|
|
90
|
+
if (admitted)
|
|
91
|
+
return admitted.relativePath;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
81
94
|
const prefix = ensureTrailingSep(base);
|
|
82
|
-
const matches =
|
|
83
|
-
? raw.slice(0, prefix.length).toLowerCase() === prefix.toLowerCase()
|
|
84
|
-
: raw.startsWith(prefix);
|
|
95
|
+
const matches = raw.startsWith(prefix);
|
|
85
96
|
if (matches) {
|
|
86
97
|
let start = prefix.length;
|
|
87
98
|
while (raw[start] === path.sep)
|
|
@@ -128,6 +139,7 @@ export async function resolvePathInRoot(root, relativePath, options) {
|
|
|
128
139
|
absolutePath: rawAbsolutePath,
|
|
129
140
|
rootPath: root.rootReal,
|
|
130
141
|
rootCanonicalPath: root.rootReal,
|
|
142
|
+
rootIdentity: root.rootIdentity,
|
|
131
143
|
boundaryLabel: "root",
|
|
132
144
|
policy: options?.allowFinalSymlink ? ROOT_PATH_ALIAS_POLICIES.unlinkTarget : undefined,
|
|
133
145
|
rejectSymlinks: options?.rejectSymlinks,
|
|
@@ -142,8 +154,23 @@ export async function resolvePathInRoot(root, relativePath, options) {
|
|
|
142
154
|
throw new FsSafeError("path-alias", "parent traversal resolves differently through a symlink");
|
|
143
155
|
}
|
|
144
156
|
}
|
|
145
|
-
if (options?.resolveCanonical)
|
|
157
|
+
if (options?.resolveCanonical) {
|
|
146
158
|
resolved = checked.canonicalPath;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// resolveRootPath preserves ordinary caller spelling as part of its
|
|
162
|
+
// public receipt. Re-admit the exact normalized spelling before it is
|
|
163
|
+
// reused for Root I/O: on a case-sensitive Windows directory it may
|
|
164
|
+
// otherwise name a distinct case-folded sibling after raw traversal.
|
|
165
|
+
const admitted = admitPathInsideRoot({
|
|
166
|
+
rootPath: root.rootReal,
|
|
167
|
+
candidatePath: checked.absolutePath,
|
|
168
|
+
rootIdentity: root.rootIdentity,
|
|
169
|
+
});
|
|
170
|
+
if (!admitted)
|
|
171
|
+
throw outsideWorkspaceError();
|
|
172
|
+
resolved = admitted.path;
|
|
173
|
+
}
|
|
147
174
|
}
|
|
148
175
|
catch (error) {
|
|
149
176
|
if (error instanceof FsSafeError && error.code === "symlink") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-directory-list.d.ts","sourceRoot":"","sources":["../src/root-directory-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAQ1C,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"root-directory-list.d.ts","sourceRoot":"","sources":["../src/root-directory-list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAQ1C,OAAO,EAA6B,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhF,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIrD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,CAcvD;AAWD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;AAClH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;AAqBhI,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,QAAQ,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC;IAClG,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,IAAI,OAAO,CAAC;CACvB,CAAC;AAEF,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,oBAAoB,CAAC,CA6J/B"}
|
|
@@ -4,9 +4,10 @@ import path from "node:path";
|
|
|
4
4
|
import { setImmediate as yieldToEventLoop } from "node:timers/promises";
|
|
5
5
|
import { assertAsyncDirectoryGuard, createAsyncDirectoryGuard } from "./directory-guard.js";
|
|
6
6
|
import { FsSafeError } from "./errors.js";
|
|
7
|
-
import { isNotFoundPathError
|
|
7
|
+
import { isNotFoundPathError } from "./path.js";
|
|
8
8
|
import { assertRootIdentityCurrent } from "./root-context.js";
|
|
9
9
|
import { rootPathChangedError } from "./root-errors.js";
|
|
10
|
+
import { admitPathInsideRoot } from "./root-boundary.js";
|
|
10
11
|
import { createSuppressedError } from "./suppressed-error.js";
|
|
11
12
|
const METADATA_BATCH_SIZE = 32;
|
|
12
13
|
export function pathStatFromStats(stat) {
|
|
@@ -52,9 +53,16 @@ export async function openRootDirectoryListing(root, directory, options) {
|
|
|
52
53
|
const guard = await createAsyncDirectoryGuard(directory, { bigint: true }).catch((error) => {
|
|
53
54
|
throw normalizeDirectoryError(error);
|
|
54
55
|
});
|
|
55
|
-
|
|
56
|
+
const admittedRealPath = admitPathInsideRoot({
|
|
57
|
+
rootPath: root.rootReal,
|
|
58
|
+
candidatePath: guard.realPath,
|
|
59
|
+
rootIdentity: root.rootIdentity,
|
|
60
|
+
});
|
|
61
|
+
if (!admittedRealPath) {
|
|
56
62
|
throw new FsSafeError("outside-workspace", "directory is outside workspace root");
|
|
57
63
|
}
|
|
64
|
+
guard.dir = admittedRealPath.path;
|
|
65
|
+
guard.realPath = admittedRealPath.path;
|
|
58
66
|
const guardPinsRoot = guard.dir === root.rootReal &&
|
|
59
67
|
guard.stat.dev === root.rootIdentity.dev && guard.stat.ino === root.rootIdentity.ino;
|
|
60
68
|
const assertCurrent = async () => {
|
package/dist/root-impl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAkC7D,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAQ9E,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EASL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAY,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAYpF,OAAO,EAEgB,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EACtF,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,KAAK,YAAY,EACnG,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EACjE,KAAK,uBAAuB,EAAE,KAAK,eAAe,EAAE,KAAK,iBAAiB,EAC1E,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EACjD,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,qBAAqB,EACzF,iBAAiB,EAAE,uBAAuB,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAC3F,eAAe,EAAE,uBAAuB,EAAE,WAAW,EAAE,eAAe,EACtE,iBAAiB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,gBAAgB,GAC5E,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,EAAE,kCAAkC,EAAE,MAAM,sBAAsB,CAAC;AAC1E,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,oBAAoB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAuKF,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAEhC,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3E,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3E,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5E,QAAQ,CACN,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,eAAe,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;KAAE,GACxD,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAClB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,eAAe,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;KAAE,GACxD,OAAO,CAAC,CAAC,CAAC,CAAC;IACd,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/E,MAAM,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzE,YAAY,CACV,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/B,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,UAAU,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,KAAK,CACH,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChH,SAAS,CACP,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,UAAU,CACR,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/F,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnF,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,aAAa,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAClF,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAC7F,IAAI,CACF,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;CAC5F;AAED,qBAAa,UAAW,YAAW,IAAI;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA8B;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAEhC,YAAY,OAAO,EAAE,WAAW,EAAE,QAAQ,GAAE,YAAiB,EAM5D;IAED,OAAO,KAAK,OAAO,GAOlB;IAED,OAAO,CAAC,eAAe;IAYjB,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKnD;IAEK,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,CAMnF;IAEK,IAAI,CACR,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAKrB;IAEK,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpF;IAEK,QAAQ,CACZ,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,eAAe,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;KAAO,GAC5D,OAAO,CAAC,MAAM,CAAC,CAGjB;IAEK,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,eAAe,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAA;KAAO,GAC5D,OAAO,CAAC,CAAC,CAAC,CAEZ;IAEK,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAKrB;IAED,MAAM,CAAC,OAAO,GAAE,eAAoB,cACV,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,CAGjD;IAEK,YAAY,CAChB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,kBAAkB,CAAC,CAW7B;IAEK,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxG;IAEK,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjF;IAEK,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAM/E;IAEK,UAAU,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9D;IAEK,KAAK,CACT,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAWf;IAEK,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChG,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAkBhH,SAAS,CACb,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAIf;IAEK,UAAU,CACd,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAIf;IAEK,MAAM,CACV,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAcf;IAEK,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUnD;IAEK,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAIlD;IAEK,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnF,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,aAAa,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAUlF,IAAI,CACR,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAkBf;IACD,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAM/F;IACD,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAWzF;CACF;AACD,wBAAsB,IAAI,CACxB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,YAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAGf;AAID,wBAAgB,sBAAsB,CACpC,KAAK,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,EACtF,QAAQ,GAAE,YAAiB,GAC1B,IAAI,CAQN;AAuED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,UAAU,CAAC,CAQtB;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAG3F;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,oBAAoB,CAAC;IAClC,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC"}
|