@openclaw/fs-safe 0.11.0 → 0.13.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 +119 -0
- package/README.md +15 -8
- package/dist/absolute-path.d.ts.map +1 -1
- package/dist/absolute-path.js +32 -11
- package/dist/advanced.d.ts +3 -1
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +3 -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-input.d.ts.map +1 -1
- package/dist/archive-input.js +6 -2
- package/dist/archive-merge.d.ts.map +1 -1
- package/dist/archive-merge.js +15 -2
- package/dist/archive-native.d.ts.map +1 -1
- package/dist/archive-native.js +7 -19
- package/dist/archive-plan.js +1 -1
- package/dist/archive-read.d.ts.map +1 -1
- package/dist/archive-read.js +55 -46
- package/dist/archive-staging.d.ts.map +1 -1
- package/dist/archive-staging.js +43 -10
- package/dist/archive-tar-inspect.d.ts.map +1 -1
- package/dist/archive-tar-inspect.js +4 -1
- package/dist/archive-zip-admission.d.ts +1 -1
- package/dist/archive-zip-admission.d.ts.map +1 -1
- package/dist/archive-zip-admission.js +2 -2
- package/dist/archive-zip-directory.d.ts +3 -0
- package/dist/archive-zip-directory.d.ts.map +1 -1
- package/dist/archive-zip-directory.js +13 -2
- package/dist/archive-zip-loader.d.ts +3 -2
- package/dist/archive-zip-loader.d.ts.map +1 -1
- package/dist/archive-zip-loader.js +30 -4
- package/dist/archive-zip-manifest.d.ts +5 -0
- package/dist/archive-zip-manifest.d.ts.map +1 -0
- package/dist/archive-zip-manifest.js +22 -0
- package/dist/archive-zip-names.d.ts +6 -1
- package/dist/archive-zip-names.d.ts.map +1 -1
- package/dist/archive-zip-names.js +50 -17
- package/dist/archive-zip-preflight.d.ts.map +1 -1
- package/dist/archive-zip-preflight.js +3 -2
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +9 -4
- package/dist/bounded-read.js +2 -2
- package/dist/darwin-acl.d.ts +4 -0
- package/dist/darwin-acl.d.ts.map +1 -0
- package/dist/darwin-acl.js +24 -0
- package/dist/deny-mutations.d.ts.map +1 -1
- package/dist/deny-mutations.js +8 -2
- package/dist/device-path.d.ts.map +1 -1
- package/dist/device-path.js +5 -3
- package/dist/directory-durability.d.ts.map +1 -1
- package/dist/directory-durability.js +67 -23
- package/dist/directory-entry-path.d.ts +3 -0
- package/dist/directory-entry-path.d.ts.map +1 -0
- package/dist/directory-entry-path.js +21 -0
- package/dist/directory-guard.d.ts +17 -1
- package/dist/directory-guard.d.ts.map +1 -1
- package/dist/directory-guard.js +134 -48
- package/dist/directory-mode-node.d.ts +12 -0
- package/dist/directory-mode-node.d.ts.map +1 -1
- package/dist/directory-mode-node.js +102 -4
- package/dist/effective-uid.d.ts +2 -0
- package/dist/effective-uid.d.ts.map +1 -0
- package/dist/effective-uid.js +25 -0
- package/dist/file-handle-transfer.d.ts.map +1 -1
- package/dist/file-handle-transfer.js +98 -27
- package/dist/file-hash.d.ts.map +1 -1
- package/dist/file-hash.js +12 -2
- package/dist/file-lock-sync.d.ts.map +1 -1
- package/dist/file-lock-sync.js +36 -6
- package/dist/file-lock.d.ts.map +1 -1
- package/dist/file-lock.js +29 -9
- package/dist/file-observation.d.ts +1 -1
- package/dist/file-observation.d.ts.map +1 -1
- package/dist/file-store-boundary.d.ts +6 -2
- package/dist/file-store-boundary.d.ts.map +1 -1
- package/dist/file-store-boundary.js +20 -65
- package/dist/file-store-copy-source.d.ts +5 -0
- package/dist/file-store-copy-source.d.ts.map +1 -0
- package/dist/file-store-copy-source.js +31 -0
- package/dist/file-store-path.d.ts.map +1 -1
- package/dist/file-store-path.js +4 -1
- package/dist/file-store-prune.d.ts.map +1 -1
- package/dist/file-store-prune.js +9 -1
- package/dist/file-store-sync-directory.d.ts +16 -0
- package/dist/file-store-sync-directory.d.ts.map +1 -0
- package/dist/file-store-sync-directory.js +349 -0
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +11 -28
- package/dist/filename.d.ts +1 -0
- package/dist/filename.d.ts.map +1 -1
- package/dist/filename.js +85 -23
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +3 -2
- package/dist/guarded-mkdir.d.ts +10 -0
- package/dist/guarded-mkdir.d.ts.map +1 -1
- package/dist/guarded-mkdir.js +217 -33
- package/dist/guest.d.ts.map +1 -1
- package/dist/guest.js +16 -5
- package/dist/home-dir.d.ts.map +1 -1
- package/dist/home-dir.js +73 -10
- package/dist/install-path.d.ts +6 -0
- package/dist/install-path.d.ts.map +1 -1
- package/dist/install-path.js +67 -19
- package/dist/json-durable-queue-ownership.d.ts +8 -0
- package/dist/json-durable-queue-ownership.d.ts.map +1 -1
- package/dist/json-durable-queue-ownership.js +134 -43
- package/dist/json-durable-queue-paths.d.ts +11 -0
- package/dist/json-durable-queue-paths.d.ts.map +1 -0
- package/dist/json-durable-queue-paths.js +42 -0
- 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 +61 -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 +83 -134
- package/dist/json-store.d.ts.map +1 -1
- package/dist/json-store.js +5 -1
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +54 -22
- package/dist/local-file-access.d.ts.map +1 -1
- package/dist/local-file-access.js +4 -0
- package/dist/local-file-descriptor.d.ts +17 -0
- package/dist/local-file-descriptor.d.ts.map +1 -0
- package/dist/local-file-descriptor.js +84 -0
- package/dist/local-roots.d.ts.map +1 -1
- package/dist/local-roots.js +35 -7
- package/dist/move-path-cleanup.d.ts +2 -0
- package/dist/move-path-cleanup.d.ts.map +1 -1
- package/dist/move-path-cleanup.js +44 -18
- package/dist/move-path.d.ts.map +1 -1
- package/dist/move-path.js +31 -6
- package/dist/native-binding.d.ts +21 -0
- package/dist/native-binding.d.ts.map +1 -1
- package/dist/native-directory-observation.d.ts +17 -0
- package/dist/native-directory-observation.d.ts.map +1 -0
- package/dist/native-directory-observation.js +37 -0
- package/dist/native-parent-admission.d.ts +31 -0
- package/dist/native-parent-admission.d.ts.map +1 -0
- package/dist/native-parent-admission.js +124 -0
- package/dist/native-pinned-write-windows.d.ts +0 -1
- package/dist/native-pinned-write-windows.d.ts.map +1 -1
- package/dist/native-pinned-write-windows.js +0 -3
- package/dist/native-pinned-write.d.ts.map +1 -1
- package/dist/native-pinned-write.js +309 -40
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +15 -5
- package/dist/overwrite-file-handle.d.ts.map +1 -1
- package/dist/overwrite-file-handle.js +5 -1
- package/dist/owner-dacl.d.ts.map +1 -1
- package/dist/owner-dacl.js +2 -0
- package/dist/path-policy.d.ts.map +1 -1
- package/dist/path-policy.js +7 -2
- package/dist/path-prefix.d.ts +7 -0
- package/dist/path-prefix.d.ts.map +1 -0
- package/dist/path-prefix.js +82 -0
- 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 +37 -0
- package/dist/path-segment-route.d.ts +7 -0
- package/dist/path-segment-route.d.ts.map +1 -0
- package/dist/path-segment-route.js +24 -0
- package/dist/path-suffix-aliases.d.ts +10 -0
- package/dist/path-suffix-aliases.d.ts.map +1 -0
- package/dist/path-suffix-aliases.js +386 -0
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +35 -6
- package/dist/permissions-windows.d.ts.map +1 -1
- package/dist/permissions-windows.js +14 -3
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +37 -8
- package/dist/pinned-mutation-admission.d.ts +25 -0
- package/dist/pinned-mutation-admission.d.ts.map +1 -0
- package/dist/pinned-mutation-admission.js +425 -0
- package/dist/pinned-mutation-observation.d.ts +34 -0
- package/dist/pinned-mutation-observation.d.ts.map +1 -0
- package/dist/pinned-mutation-observation.js +142 -0
- package/dist/pinned-mutation-shared-route.d.ts +24 -0
- package/dist/pinned-mutation-shared-route.d.ts.map +1 -0
- package/dist/pinned-mutation-shared-route.js +70 -0
- package/dist/pinned-open.d.ts +6 -0
- package/dist/pinned-open.d.ts.map +1 -1
- package/dist/pinned-open.js +28 -10
- package/dist/pinned-write-types.d.ts +75 -0
- package/dist/pinned-write-types.d.ts.map +1 -0
- package/dist/pinned-write-types.js +1 -0
- package/dist/pinned-write.d.ts +7 -33
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +152 -17
- package/dist/private-directory.d.ts.map +1 -1
- package/dist/private-directory.js +2 -0
- package/dist/private-producer-handoff.d.ts +16 -0
- package/dist/private-producer-handoff.d.ts.map +1 -0
- package/dist/private-producer-handoff.js +272 -0
- package/dist/private-temp-workspace.d.ts +2 -39
- package/dist/private-temp-workspace.d.ts.map +1 -1
- package/dist/private-temp-workspace.js +183 -77
- package/dist/publish-file.d.ts.map +1 -1
- package/dist/publish-file.js +33 -29
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +56 -45
- package/dist/replace-directory.d.ts.map +1 -1
- package/dist/replace-directory.js +12 -5
- package/dist/replace-file-temp-owner.d.ts +1 -0
- package/dist/replace-file-temp-owner.d.ts.map +1 -1
- package/dist/replace-file-temp-owner.js +12 -1
- package/dist/replace-file.d.ts.map +1 -1
- package/dist/replace-file.js +24 -24
- package/dist/root-boundary.d.ts +29 -0
- package/dist/root-boundary.d.ts.map +1 -0
- package/dist/root-boundary.js +182 -0
- package/dist/root-context.d.ts +12 -1
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-context.js +89 -16
- package/dist/root-directory-creation.d.ts +13 -0
- package/dist/root-directory-creation.d.ts.map +1 -0
- package/dist/root-directory-creation.js +212 -0
- package/dist/root-directory-list.d.ts +16 -4
- package/dist/root-directory-list.d.ts.map +1 -1
- package/dist/root-directory-list.js +182 -33
- package/dist/root-directory.d.ts +23 -0
- package/dist/root-directory.d.ts.map +1 -0
- package/dist/root-directory.js +141 -0
- package/dist/root-errors.d.ts.map +1 -1
- package/dist/root-errors.js +12 -1
- package/dist/root-file-final-admission.d.ts +21 -0
- package/dist/root-file-final-admission.d.ts.map +1 -0
- package/dist/root-file-final-admission.js +83 -0
- package/dist/root-file.d.ts.map +1 -1
- package/dist/root-file.js +103 -24
- package/dist/root-impl.d.ts +1 -0
- package/dist/root-impl.d.ts.map +1 -1
- package/dist/root-impl.js +316 -325
- package/dist/root-move-noreplace.d.ts +14 -0
- package/dist/root-move-noreplace.d.ts.map +1 -0
- package/dist/root-move-noreplace.js +202 -0
- 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-observed-path.d.ts +9 -0
- package/dist/root-observed-path.d.ts.map +1 -0
- package/dist/root-observed-path.js +95 -0
- package/dist/root-path-errors.d.ts +12 -0
- package/dist/root-path-errors.d.ts.map +1 -0
- package/dist/root-path-errors.js +13 -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 +63 -22
- package/dist/root-path-observation.d.ts +63 -0
- package/dist/root-path-observation.d.ts.map +1 -0
- package/dist/root-path-observation.js +180 -0
- package/dist/root-path-stat.d.ts +5 -0
- package/dist/root-path-stat.d.ts.map +1 -0
- package/dist/root-path-stat.js +101 -0
- package/dist/root-path-symlink.d.ts.map +1 -1
- package/dist/root-path-symlink.js +23 -4
- package/dist/root-path.d.ts +13 -0
- package/dist/root-path.d.ts.map +1 -1
- package/dist/root-path.js +263 -73
- package/dist/root-paths-lexical.d.ts +9 -0
- package/dist/root-paths-lexical.d.ts.map +1 -0
- package/dist/root-paths-lexical.js +22 -0
- package/dist/root-paths.d.ts +3 -29
- package/dist/root-paths.d.ts.map +1 -1
- package/dist/root-paths.js +89 -178
- package/dist/root-read-admission.d.ts +26 -0
- package/dist/root-read-admission.d.ts.map +1 -0
- package/dist/root-read-admission.js +94 -0
- package/dist/root-remove-identity.d.ts +15 -0
- package/dist/root-remove-identity.d.ts.map +1 -0
- package/dist/root-remove-identity.js +89 -0
- package/dist/root-remove-receipt.d.ts +17 -0
- package/dist/root-remove-receipt.d.ts.map +1 -0
- package/dist/root-remove-receipt.js +37 -0
- package/dist/root-remove.d.ts +2 -1
- package/dist/root-remove.d.ts.map +1 -1
- package/dist/root-remove.js +172 -10
- package/dist/root-walk.d.ts.map +1 -1
- package/dist/root-walk.js +2 -1
- package/dist/root-write-admission.d.ts +68 -0
- package/dist/root-write-admission.d.ts.map +1 -0
- package/dist/root-write-admission.js +322 -0
- package/dist/root-write-compatibility.d.ts +13 -0
- package/dist/root-write-compatibility.d.ts.map +1 -0
- package/dist/root-write-compatibility.js +74 -0
- package/dist/root-write-complete-parent.d.ts +42 -0
- package/dist/root-write-complete-parent.d.ts.map +1 -0
- package/dist/root-write-complete-parent.js +195 -0
- 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-publication.d.ts +24 -0
- package/dist/root-write-publication.d.ts.map +1 -0
- package/dist/root-write-publication.js +85 -0
- package/dist/root-write-verification.d.ts.map +1 -1
- package/dist/root-write-verification.js +18 -7
- package/dist/safe-path-segment.d.ts.map +1 -1
- package/dist/safe-path-segment.js +3 -1
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +62 -24
- package/dist/secret-read-async.d.ts.map +1 -1
- package/dist/secret-read-async.js +18 -13
- package/dist/secret-read-policy.d.ts.map +1 -1
- package/dist/secret-read-policy.js +5 -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 +98 -10
- package/dist/secure-temp-dir.d.ts +6 -3
- package/dist/secure-temp-dir.d.ts.map +1 -1
- package/dist/secure-temp-dir.js +121 -101
- package/dist/secure-temp-repair.d.ts +35 -0
- package/dist/secure-temp-repair.d.ts.map +1 -0
- package/dist/secure-temp-repair.js +106 -0
- package/dist/sibling-staged-file.d.ts +3 -1
- package/dist/sibling-staged-file.d.ts.map +1 -1
- package/dist/sibling-staged-file.js +181 -50
- package/dist/sibling-temp.d.ts.map +1 -1
- package/dist/sibling-temp.js +27 -12
- package/dist/sidecar-lock-acquire.d.ts.map +1 -1
- package/dist/sidecar-lock-acquire.js +45 -15
- package/dist/sidecar-lock-root.d.ts.map +1 -1
- package/dist/sidecar-lock-root.js +4 -2
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +2 -3
- package/dist/staged-directory.d.ts +14 -5
- package/dist/staged-directory.d.ts.map +1 -1
- package/dist/staged-directory.js +54 -3
- package/dist/standalone-publication-path.d.ts +2 -0
- package/dist/standalone-publication-path.d.ts.map +1 -0
- package/dist/standalone-publication-path.js +6 -0
- package/dist/stat-observation.d.ts +11 -0
- package/dist/stat-observation.d.ts.map +1 -0
- package/dist/stat-observation.js +64 -0
- package/dist/strict-file-identity.d.ts.map +1 -1
- package/dist/strict-file-identity.js +39 -2
- package/dist/symlink-parents.d.ts.map +1 -1
- package/dist/symlink-parents.js +7 -2
- package/dist/temp-target.d.ts +2 -0
- package/dist/temp-target.d.ts.map +1 -1
- package/dist/temp-target.js +133 -4
- package/dist/temp-workspace-admission.d.ts +22 -0
- package/dist/temp-workspace-admission.d.ts.map +1 -0
- package/dist/temp-workspace-admission.js +374 -0
- package/dist/temp-workspace-child-admission.d.ts +13 -0
- package/dist/temp-workspace-child-admission.d.ts.map +1 -0
- package/dist/temp-workspace-child-admission.js +95 -0
- package/dist/temp-workspace-descriptor.d.ts +48 -0
- package/dist/temp-workspace-descriptor.d.ts.map +1 -0
- package/dist/temp-workspace-descriptor.js +363 -0
- package/dist/temp-workspace-identity.d.ts +15 -0
- package/dist/temp-workspace-identity.d.ts.map +1 -0
- package/dist/temp-workspace-identity.js +41 -0
- package/dist/temp-workspace-owner.d.ts +7 -6
- package/dist/temp-workspace-owner.d.ts.map +1 -1
- package/dist/temp-workspace-owner.js +121 -61
- package/dist/temp-workspace-permissions.d.ts +4 -0
- package/dist/temp-workspace-permissions.d.ts.map +1 -0
- package/dist/temp-workspace-permissions.js +32 -0
- package/dist/temp-workspace-types.d.ts +40 -0
- package/dist/temp-workspace-types.d.ts.map +1 -0
- package/dist/temp-workspace-types.js +1 -0
- package/dist/temp.d.ts +1 -1
- package/dist/temp.d.ts.map +1 -1
- package/dist/temp.js +1 -1
- package/dist/test-hooks.d.ts +7 -0
- package/dist/test-hooks.d.ts.map +1 -1
- package/dist/text-atomic.d.ts.map +1 -1
- package/dist/text-atomic.js +3 -1
- package/dist/trash.d.ts.map +1 -1
- package/dist/trash.js +54 -8
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +20 -16
- package/dist/windows-owner.d.ts.map +1 -1
- package/dist/windows-owner.js +5 -0
- package/dist/windows-path-alias.d.ts +39 -0
- package/dist/windows-path-alias.d.ts.map +1 -0
- package/dist/windows-path-alias.js +153 -0
- package/docs/advanced.md +28 -1
- package/docs/archive.md +29 -2
- package/docs/atomic.md +27 -3
- package/docs/contributing.md +4 -1
- package/docs/copy.md +4 -1
- package/docs/durability.md +18 -2
- package/docs/errors.md +14 -6
- package/docs/file-store.md +30 -3
- package/docs/filename.md +21 -7
- package/docs/guest.md +5 -0
- package/docs/install-path.md +61 -15
- package/docs/install.md +12 -8
- package/docs/json-store.md +5 -1
- package/docs/json.md +11 -0
- package/docs/mutation-policy-proof.md +65 -0
- package/docs/native-helper.md +28 -9
- package/docs/native.md +46 -10
- package/docs/output.md +33 -11
- package/docs/path-prefix.md +64 -0
- package/docs/path-suffix-aliases.md +159 -0
- package/docs/path.md +12 -1
- package/docs/permissions.md +26 -1
- package/docs/private-file-store.md +14 -0
- package/docs/public-api.md +14 -0
- package/docs/quickstart.md +1 -1
- package/docs/reading.md +8 -1
- package/docs/root.md +21 -4
- package/docs/secret-file.md +3 -0
- package/docs/secure-file.md +21 -16
- package/docs/security-model.md +76 -9
- package/docs/sidecar-lock.md +28 -1
- package/docs/store.md +27 -2
- package/docs/temp.md +262 -34
- package/docs/test-hooks.md +14 -0
- package/docs/writing.md +38 -8
- package/package.json +10 -10
package/dist/secure-temp-dir.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { tmpdir as getOsTmpDir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { directoryEntryPath } from "./directory-entry-path.js";
|
|
4
5
|
import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
|
|
5
6
|
import { assertSafePathSegment } from "./safe-path-segment.js";
|
|
7
|
+
import { assertNoWindowsPathAlias, pathForWindowsFilesystem } from "./windows-path-alias.js";
|
|
8
|
+
import { captureSecureTempRepairAdapter, repairSecureTempDirectory, secureTempDirectoryReceipt, } from "./secure-temp-repair.js";
|
|
6
9
|
function isNodeErrorWithCode(err, code) {
|
|
7
10
|
return (typeof err === "object" &&
|
|
8
11
|
err !== null &&
|
|
@@ -10,152 +13,169 @@ function isNodeErrorWithCode(err, code) {
|
|
|
10
13
|
err.code === code);
|
|
11
14
|
}
|
|
12
15
|
export function resolveSecureTempRoot(options) {
|
|
13
|
-
const fallbackPrefix =
|
|
16
|
+
const { fallbackPrefix: prefix, accessSync: suppliedAccess, lstatSync: suppliedLstat, mkdirSync: suppliedMkdir, descriptor: suppliedDescriptor, getuid: suppliedGetuid, tmpdir: suppliedTmpdir, platform: suppliedPlatform, preferredDir, skipPreferredOnWindows, warn: suppliedWarn, warningPrefix: suppliedWarningPrefix, unsafeFallbackLabel: suppliedFallbackLabel, } = options;
|
|
17
|
+
const platform = suppliedPlatform ?? process.platform;
|
|
18
|
+
const windows = process.platform === "win32" || platform === "win32";
|
|
19
|
+
// A platform adapter cannot disable the host's Windows pathname policy.
|
|
20
|
+
const admissionPlatform = process.platform === "win32" ? process.platform : platform;
|
|
21
|
+
const capturedDescriptor = captureSecureTempRepairAdapter(suppliedDescriptor, suppliedAccess !== undefined || suppliedLstat !== undefined || suppliedMkdir !== undefined);
|
|
22
|
+
const descriptor = windows ? undefined : capturedDescriptor;
|
|
23
|
+
const hostLstat = fs.lstatSync;
|
|
24
|
+
const hostAccess = fs.accessSync;
|
|
25
|
+
const hostMkdir = fs.mkdirSync;
|
|
26
|
+
const hostGetuid = process.getuid;
|
|
27
|
+
const accessSync = suppliedAccess ?? (process.platform === "win32"
|
|
28
|
+
? (candidate, mode) => hostAccess(pathForWindowsFilesystem(candidate), mode)
|
|
29
|
+
: hostAccess);
|
|
30
|
+
const lstatSync = descriptor
|
|
31
|
+
? (candidate) => descriptor.lstatSync(candidate, { bigint: true })
|
|
32
|
+
: suppliedLstat ?? ((candidate) => windows
|
|
33
|
+
? hostLstat(pathForWindowsFilesystem(candidate))
|
|
34
|
+
: hostLstat(candidate, { bigint: true }));
|
|
35
|
+
// Virtual observations cannot authorize host creation. A supplied mkdir hook
|
|
36
|
+
// is explicit authority; chmodSync is deprecated and deliberately not read.
|
|
37
|
+
const mkdirSync = suppliedMkdir ?? (suppliedLstat !== undefined || suppliedAccess !== undefined || suppliedDescriptor !== undefined
|
|
38
|
+
? undefined
|
|
39
|
+
: (directory, mkdirOptions) => hostMkdir(recursiveMkdirPath(pathForWindowsFilesystem(directory)), mkdirOptions));
|
|
40
|
+
const warn = suppliedWarn ?? console.warn.bind(console);
|
|
41
|
+
const warningPrefix = suppliedWarningPrefix ?? "[fs-safe]";
|
|
42
|
+
const unsafeFallbackLabel = suppliedFallbackLabel ?? "secure temp dir";
|
|
43
|
+
const tmpdir = typeof suppliedTmpdir === "function" ? suppliedTmpdir : getOsTmpDir;
|
|
44
|
+
const getuid = suppliedGetuid ?? (() => {
|
|
45
|
+
try {
|
|
46
|
+
return typeof hostGetuid === "function" ? hostGetuid.call(process) : undefined;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const fallbackPrefix = assertSafePathSegment(prefix, {
|
|
14
53
|
allowDotPrefix: true,
|
|
15
54
|
label: "fallback temp prefix",
|
|
16
55
|
});
|
|
17
56
|
const TMP_DIR_ACCESS_MODE = fs.constants.W_OK | fs.constants.X_OK;
|
|
18
|
-
const accessSync = options.accessSync ?? fs.accessSync;
|
|
19
|
-
const chmodSync = options.chmodSync ?? fs.chmodSync;
|
|
20
|
-
const lstatSync = options.lstatSync ?? fs.lstatSync;
|
|
21
|
-
const mkdirSync = options.mkdirSync ?? ((directory, mkdirOptions) => fs.mkdirSync(recursiveMkdirPath(directory), mkdirOptions));
|
|
22
|
-
const warn = options.warn ?? ((message) => console.warn(message));
|
|
23
|
-
const warningPrefix = options.warningPrefix ?? "[fs-safe]";
|
|
24
|
-
const unsafeFallbackLabel = options.unsafeFallbackLabel ?? "secure temp dir";
|
|
25
|
-
const getuid = options.getuid ??
|
|
26
|
-
(() => {
|
|
27
|
-
try {
|
|
28
|
-
return typeof process.getuid === "function" ? process.getuid() : undefined;
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
const tmpdir = typeof options.tmpdir === "function" ? options.tmpdir : getOsTmpDir;
|
|
35
|
-
const platform = options.platform ?? process.platform;
|
|
36
57
|
const uid = getuid();
|
|
58
|
+
if (uid !== undefined && (!Number.isSafeInteger(uid) || uid < 0)) {
|
|
59
|
+
throw new Error("Secure temp directory user identity is invalid.");
|
|
60
|
+
}
|
|
61
|
+
if (preferredDir !== undefined) {
|
|
62
|
+
assertNoWindowsPathAlias(preferredDir, "filesystem", "preferred temp directory uses a Windows filesystem namespace alias", admissionPlatform);
|
|
63
|
+
}
|
|
37
64
|
const isSecureDirForUser = (st) => {
|
|
38
|
-
if (uid === undefined)
|
|
65
|
+
if (windows || uid === undefined)
|
|
39
66
|
return true;
|
|
40
|
-
}
|
|
41
|
-
if (
|
|
67
|
+
const { uid: owner, mode } = st;
|
|
68
|
+
if (owner !== undefined && owner !== uid && owner !== BigInt(uid))
|
|
42
69
|
return false;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return true;
|
|
70
|
+
if (typeof mode === "bigint")
|
|
71
|
+
return mode >= 0n && (mode & 18n) === 0n;
|
|
72
|
+
return mode === undefined || (Number.isSafeInteger(mode) && mode >= 0 && (mode & 0o022) === 0);
|
|
48
73
|
};
|
|
49
74
|
const fallback = () => {
|
|
50
75
|
const base = tmpdir();
|
|
76
|
+
assertNoWindowsPathAlias(base, "filesystem", "system temp directory uses a Windows filesystem namespace alias", admissionPlatform);
|
|
51
77
|
const suffix = uid === undefined ? fallbackPrefix : `${fallbackPrefix}-${uid}`;
|
|
52
78
|
const joiner = platform === "win32" ? path.win32.join : path.join;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return st.isDirectory() && !st.isSymbolicLink() && isSecureDirForUser(st);
|
|
79
|
+
const fallbackPath = joiner(base, suffix);
|
|
80
|
+
assertNoWindowsPathAlias(fallbackPath, "filesystem", "fallback temp directory uses a Windows filesystem namespace alias", admissionPlatform);
|
|
81
|
+
return fallbackPath;
|
|
57
82
|
};
|
|
58
83
|
const resolveDirState = (candidatePath) => {
|
|
84
|
+
assertNoWindowsPathAlias(candidatePath, "filesystem", "temp directory uses a Windows filesystem namespace alias", admissionPlatform);
|
|
85
|
+
let candidate;
|
|
59
86
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
87
|
+
candidate = lstatSync(candidatePath);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return { kind: isNodeErrorWithCode(error, "ENOENT") ? "missing" : "invalid", error };
|
|
91
|
+
}
|
|
92
|
+
let receipt;
|
|
93
|
+
try {
|
|
94
|
+
if (descriptor && uid !== undefined) {
|
|
95
|
+
receipt = secureTempDirectoryReceipt(candidate, uid);
|
|
96
|
+
}
|
|
97
|
+
if (receipt ? (receipt.mode & 18n) !== 0n :
|
|
98
|
+
candidate.isDirectory() !== true || candidate.isSymbolicLink() !== false || !isSecureDirForUser(candidate)) {
|
|
99
|
+
return { kind: "invalid", receipt };
|
|
63
100
|
}
|
|
64
101
|
accessSync(candidatePath, TMP_DIR_ACCESS_MODE);
|
|
65
|
-
return "available";
|
|
102
|
+
return { kind: "available", receipt };
|
|
66
103
|
}
|
|
67
|
-
catch (
|
|
68
|
-
|
|
69
|
-
return "missing";
|
|
70
|
-
}
|
|
71
|
-
return "invalid";
|
|
104
|
+
catch (error) {
|
|
105
|
+
return { kind: "invalid", receipt, error };
|
|
72
106
|
}
|
|
73
107
|
};
|
|
74
|
-
const
|
|
108
|
+
const tryRepair = (candidatePath, state, finalize = false) => {
|
|
109
|
+
assertNoWindowsPathAlias(candidatePath, "filesystem", "temp directory uses a Windows filesystem namespace alias", admissionPlatform);
|
|
110
|
+
if (!descriptor || uid === undefined || !state.receipt) {
|
|
111
|
+
return finalize ? { kind: "invalid", error: new Error("Secure temp descriptor finalization is unavailable.") } : state;
|
|
112
|
+
}
|
|
75
113
|
try {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
if (uid !== undefined && typeof st.uid === "number" && st.uid !== uid) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
if (typeof st.mode !== "number") {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
if ((st.mode & 0o022) === 0) {
|
|
87
|
-
return resolveDirState(candidatePath) === "available";
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
chmodSync(candidatePath, 0o700);
|
|
91
|
-
}
|
|
92
|
-
catch (chmodErr) {
|
|
93
|
-
if (isNodeErrorWithCode(chmodErr, "EPERM") ||
|
|
94
|
-
isNodeErrorWithCode(chmodErr, "EACCES") ||
|
|
95
|
-
isNodeErrorWithCode(chmodErr, "ENOENT")) {
|
|
96
|
-
return resolveDirState(candidatePath) === "available";
|
|
97
|
-
}
|
|
98
|
-
throw chmodErr;
|
|
99
|
-
}
|
|
100
|
-
warn(`${warningPrefix} tightened permissions on temp dir: ${candidatePath}`);
|
|
101
|
-
return resolveDirState(candidatePath) === "available";
|
|
114
|
+
repairSecureTempDirectory(candidatePath, state.receipt, uid, descriptor, () => accessSync(candidatePath, TMP_DIR_ACCESS_MODE), () => warn(`${warningPrefix} tightened permissions on temp dir: ${candidatePath}`), finalize);
|
|
115
|
+
return { kind: "available" };
|
|
102
116
|
}
|
|
103
|
-
catch {
|
|
104
|
-
return
|
|
117
|
+
catch (error) {
|
|
118
|
+
return { kind: "invalid", error };
|
|
105
119
|
}
|
|
106
120
|
};
|
|
107
121
|
const ensureTrustedFallbackDir = () => {
|
|
108
122
|
const fallbackPath = fallback();
|
|
109
|
-
const
|
|
110
|
-
|
|
123
|
+
const entryPath = directoryEntryPath(fallbackPath, windows ? "win32" : platform);
|
|
124
|
+
let state = resolveDirState(entryPath);
|
|
125
|
+
let finalize = false;
|
|
126
|
+
if (state.kind === "available")
|
|
111
127
|
return fallbackPath;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
if (state.kind === "missing") {
|
|
129
|
+
try {
|
|
130
|
+
if (!mkdirSync)
|
|
131
|
+
throw new Error("Secure temp creation requires an explicit filesystem adapter.");
|
|
132
|
+
const created = mkdirSync(entryPath, { recursive: true, mode: 0o700 });
|
|
133
|
+
finalize = !windows && (suppliedMkdir !== undefined || created !== undefined);
|
|
116
134
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
throw new Error(`Unable to create fallback ${unsafeFallbackLabel}: ${fallbackPath}`);
|
|
135
|
+
catch (cause) {
|
|
136
|
+
throw new Error(`Unable to create fallback ${unsafeFallbackLabel}: ${fallbackPath}`, { cause });
|
|
137
|
+
}
|
|
138
|
+
// A concurrent mkdir winner has no implicit ownership or mode authority.
|
|
139
|
+
state = resolveDirState(entryPath);
|
|
140
|
+
if (state.kind === "available" && !finalize)
|
|
141
|
+
return fallbackPath;
|
|
125
142
|
}
|
|
126
|
-
|
|
127
|
-
|
|
143
|
+
state = tryRepair(entryPath, state, finalize);
|
|
144
|
+
if (state.kind !== "available") {
|
|
145
|
+
throw new Error(`Unsafe fallback ${unsafeFallbackLabel}: ${fallbackPath}`, { cause: state.error });
|
|
128
146
|
}
|
|
129
147
|
return fallbackPath;
|
|
130
148
|
};
|
|
131
|
-
if (
|
|
149
|
+
if (skipPreferredOnWindows === true && platform === "win32") {
|
|
132
150
|
return ensureTrustedFallbackDir();
|
|
133
151
|
}
|
|
134
|
-
if (!
|
|
152
|
+
if (!preferredDir) {
|
|
135
153
|
return ensureTrustedFallbackDir();
|
|
136
154
|
}
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
155
|
+
const entryPath = directoryEntryPath(preferredDir, windows ? "win32" : platform);
|
|
156
|
+
const existingPreferredState = resolveDirState(entryPath);
|
|
157
|
+
if (existingPreferredState.kind === "available") {
|
|
158
|
+
return preferredDir;
|
|
140
159
|
}
|
|
141
|
-
if (existingPreferredState === "invalid") {
|
|
142
|
-
if (
|
|
143
|
-
return
|
|
160
|
+
if (existingPreferredState.kind === "invalid") {
|
|
161
|
+
if (tryRepair(entryPath, existingPreferredState).kind === "available") {
|
|
162
|
+
return preferredDir;
|
|
144
163
|
}
|
|
145
164
|
return ensureTrustedFallbackDir();
|
|
146
165
|
}
|
|
166
|
+
let preferredAvailable = false;
|
|
147
167
|
try {
|
|
148
|
-
const preferredParentDir = path.dirname(
|
|
168
|
+
const preferredParentDir = (windows ? path.win32 : path).dirname(entryPath);
|
|
149
169
|
accessSync(preferredParentDir, TMP_DIR_ACCESS_MODE);
|
|
150
|
-
mkdirSync
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
170
|
+
if (mkdirSync) {
|
|
171
|
+
const created = mkdirSync(entryPath, { recursive: true, mode: 0o700 });
|
|
172
|
+
const finalize = !windows && (suppliedMkdir !== undefined || created !== undefined);
|
|
173
|
+
const state = resolveDirState(entryPath);
|
|
174
|
+
preferredAvailable = (!finalize && state.kind === "available") || tryRepair(entryPath, state, finalize).kind === "available";
|
|
155
175
|
}
|
|
156
|
-
return options.preferredDir;
|
|
157
176
|
}
|
|
158
177
|
catch {
|
|
159
|
-
|
|
178
|
+
// A failed preferred path never relaxes fallback admission.
|
|
160
179
|
}
|
|
180
|
+
return preferredAvailable ? preferredDir : ensureTrustedFallbackDir();
|
|
161
181
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type BigIntStats } from "node:fs";
|
|
2
|
+
type ExactDirectoryStat = Pick<BigIntStats, "dev" | "ino" | "uid" | "mode" | "isDirectory" | "isSymbolicLink">;
|
|
3
|
+
/** Complete, synchronous descriptor authority for secure-temp admission and repair. */
|
|
4
|
+
export type SecureTempRootDescriptorAdapter = {
|
|
5
|
+
lstatSync(path: string, options: {
|
|
6
|
+
bigint: true;
|
|
7
|
+
}): ExactDirectoryStat;
|
|
8
|
+
fstatSync(fd: number, options: {
|
|
9
|
+
bigint: true;
|
|
10
|
+
}): ExactDirectoryStat;
|
|
11
|
+
openSync(path: string, flags: number): number;
|
|
12
|
+
fchmodSync(fd: number, mode: number): void;
|
|
13
|
+
closeSync(fd: number): void;
|
|
14
|
+
constants: {
|
|
15
|
+
O_RDONLY: number;
|
|
16
|
+
O_DIRECTORY: number;
|
|
17
|
+
O_NOFOLLOW: number;
|
|
18
|
+
O_NONBLOCK: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type SecureTempDirectoryReceipt = Readonly<{
|
|
22
|
+
dev: bigint;
|
|
23
|
+
ino: bigint;
|
|
24
|
+
uid: bigint;
|
|
25
|
+
mode: bigint;
|
|
26
|
+
}>;
|
|
27
|
+
export type SecureTempRepairAdapter = Omit<SecureTempRootDescriptorAdapter, "constants"> & {
|
|
28
|
+
flags: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function captureSecureTempRepairAdapter(supplied: SecureTempRootDescriptorAdapter | undefined, hasLegacyFsHooks: boolean): SecureTempRepairAdapter | undefined;
|
|
31
|
+
export declare function secureTempDirectoryReceipt(stat: ExactDirectoryStat, uid: number): SecureTempDirectoryReceipt;
|
|
32
|
+
/** No pathname chmod, search-only descriptors, procfs, or reopening fallback. */
|
|
33
|
+
export declare function repairSecureTempDirectory(candidate: string, expected: SecureTempDirectoryReceipt, uid: number, adapter: SecureTempRepairAdapter, access: () => void, repaired: () => void, finalize?: boolean): void;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=secure-temp-repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure-temp-repair.d.ts","sourceRoot":"","sources":["../src/secure-temp-repair.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/C,KAAK,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,aAAa,GAAG,gBAAgB,CAAC,CAAC;AAE/G,uFAAuF;AACvF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,IAAI,CAAA;KAAE,GAAG,kBAAkB,CAAC;IACvE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,IAAI,CAAA;KAAE,GAAG,kBAAkB,CAAC;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9C,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9F,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAC3G,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,+BAA+B,EAAE,WAAW,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7G,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,+BAA+B,GAAG,SAAS,EACrD,gBAAgB,EAAE,OAAO,GACxB,uBAAuB,GAAG,SAAS,CAarC;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,GAAG,0BAA0B,CAS5G;AAgBD,iFAAiF;AACjF,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,0BAA0B,EACpC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,uBAAuB,EAChC,MAAM,EAAE,MAAM,IAAI,EAClB,QAAQ,EAAE,MAAM,IAAI,EACpB,QAAQ,UAAQ,GACf,IAAI,CAuDN"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import fs, {} from "node:fs";
|
|
2
|
+
export function captureSecureTempRepairAdapter(supplied, hasLegacyFsHooks) {
|
|
3
|
+
if (supplied === undefined && hasLegacyFsHooks)
|
|
4
|
+
return undefined;
|
|
5
|
+
if (supplied !== undefined && (supplied === null || (typeof supplied !== "object" && typeof supplied !== "function")))
|
|
6
|
+
return undefined;
|
|
7
|
+
const source = supplied === undefined ? fs : supplied;
|
|
8
|
+
const { lstatSync, fstatSync, openSync, fchmodSync, closeSync, constants } = source;
|
|
9
|
+
const { O_RDONLY, O_DIRECTORY, O_NOFOLLOW, O_NONBLOCK } = constants ?? {};
|
|
10
|
+
if ([lstatSync, fstatSync, openSync, fchmodSync, closeSync].some((fn) => typeof fn !== "function") ||
|
|
11
|
+
O_RDONLY !== 0 || [O_DIRECTORY, O_NOFOLLOW, O_NONBLOCK].some((flag) => !Number.isSafeInteger(flag) || flag <= 0 || flag > 0x7fff_ffff) ||
|
|
12
|
+
(O_DIRECTORY & O_NOFOLLOW) !== 0 || (O_DIRECTORY & O_NONBLOCK) !== 0 || (O_NOFOLLOW & O_NONBLOCK) !== 0) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return { lstatSync, fstatSync, openSync, fchmodSync, closeSync, flags: O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_NONBLOCK };
|
|
16
|
+
}
|
|
17
|
+
export function secureTempDirectoryReceipt(stat, uid) {
|
|
18
|
+
const { dev, ino, uid: owner, mode } = stat;
|
|
19
|
+
if (typeof dev !== "bigint" || dev < 0n || typeof ino !== "bigint" || ino <= 0n ||
|
|
20
|
+
typeof owner !== "bigint" || owner !== BigInt(uid) || typeof mode !== "bigint" ||
|
|
21
|
+
mode < 0n || mode > 0xffffffffn || (mode & 61440n) !== 16384n ||
|
|
22
|
+
stat.isDirectory() !== true || stat.isSymbolicLink() !== false) {
|
|
23
|
+
throw new Error("Secure temp directory identity, owner, or type could not be verified.");
|
|
24
|
+
}
|
|
25
|
+
return { dev, ino, uid: owner, mode };
|
|
26
|
+
}
|
|
27
|
+
function assertSameDirectory(stat, expected, uid) {
|
|
28
|
+
const observed = secureTempDirectoryReceipt(stat, uid);
|
|
29
|
+
if (observed.dev !== expected.dev || observed.ino !== expected.ino || observed.uid !== expected.uid) {
|
|
30
|
+
throw new Error("Secure temp directory changed during repair.");
|
|
31
|
+
}
|
|
32
|
+
return observed;
|
|
33
|
+
}
|
|
34
|
+
function mayHaveConcurrentRepair(error) {
|
|
35
|
+
if (typeof error !== "object" || error === null || !("code" in error))
|
|
36
|
+
return false;
|
|
37
|
+
const code = error.code;
|
|
38
|
+
return code === "EPERM" || code === "EACCES" || code === "ENOENT";
|
|
39
|
+
}
|
|
40
|
+
/** No pathname chmod, search-only descriptors, procfs, or reopening fallback. */
|
|
41
|
+
export function repairSecureTempDirectory(candidate, expected, uid, adapter, access, repaired, finalize = false) {
|
|
42
|
+
assertSameDirectory(adapter.lstatSync(candidate, { bigint: true }), expected, uid);
|
|
43
|
+
const fd = adapter.openSync(candidate, adapter.flags);
|
|
44
|
+
if (!Number.isSafeInteger(fd) || fd < 0)
|
|
45
|
+
throw new Error("Secure temp directory descriptor is invalid.");
|
|
46
|
+
const errors = [];
|
|
47
|
+
try {
|
|
48
|
+
const inspect = () => {
|
|
49
|
+
const opened = assertSameDirectory(adapter.fstatSync(fd, { bigint: true }), expected, uid);
|
|
50
|
+
const named = assertSameDirectory(adapter.lstatSync(candidate, { bigint: true }), expected, uid);
|
|
51
|
+
return { opened, named };
|
|
52
|
+
};
|
|
53
|
+
const verify = (requireExactMode) => {
|
|
54
|
+
const check = () => {
|
|
55
|
+
const { opened, named } = inspect();
|
|
56
|
+
for (const stat of [opened, named]) {
|
|
57
|
+
if ((stat.mode & 18n) !== 0n || (requireExactMode && (stat.mode & 4095n) !== 448n)) {
|
|
58
|
+
throw new Error("Secure temp directory permissions remain unsafe.");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
check();
|
|
63
|
+
access();
|
|
64
|
+
check();
|
|
65
|
+
};
|
|
66
|
+
const { opened } = inspect();
|
|
67
|
+
const needsChmod = finalize ? (opened.mode & 4095n) !== 448n :
|
|
68
|
+
(opened.mode & 18n) !== 0n || (opened.mode & 448n) !== 448n;
|
|
69
|
+
let chmodError;
|
|
70
|
+
let chmodFailed = false;
|
|
71
|
+
if (needsChmod) {
|
|
72
|
+
try {
|
|
73
|
+
adapter.fchmodSync(fd, 0o700);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (!mayHaveConcurrentRepair(error))
|
|
77
|
+
throw error;
|
|
78
|
+
chmodFailed = true;
|
|
79
|
+
chmodError = error;
|
|
80
|
+
}
|
|
81
|
+
if (!chmodFailed)
|
|
82
|
+
repaired();
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
verify(finalize || (needsChmod && !chmodFailed));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (chmodFailed)
|
|
89
|
+
throw new AggregateError([chmodError, error], "Secure temp directory chmod and verification failed.");
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
errors.push(error);
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
adapter.closeSync(fd);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
errors.push(error);
|
|
101
|
+
}
|
|
102
|
+
if (errors.length > 1)
|
|
103
|
+
throw new AggregateError(errors, "Secure temp directory repair and close failed.");
|
|
104
|
+
if (errors.length === 1)
|
|
105
|
+
throw errors[0];
|
|
106
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
export declare function resolveCallbackTempPath(workspaceDir: string, component: string): string;
|
|
1
2
|
export declare function writeCallbackSibling<T>(params: {
|
|
2
|
-
|
|
3
|
+
tempDir: string;
|
|
4
|
+
tempName: string;
|
|
3
5
|
write: (tempPath: string) => Promise<T>;
|
|
4
6
|
producerIsolation?: "private-directory";
|
|
5
7
|
resolveFinalPath: (result: T) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sibling-staged-file.d.ts","sourceRoot":"","sources":["../src/sibling-staged-file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sibling-staged-file.d.ts","sourceRoot":"","sources":["../src/sibling-staged-file.ts"],"names":[],"mappings":"AAsCA,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAoBvF;AAsHD,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACxC,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,CAAC,CAsK3C"}
|