windows-development-sandbox 1.5.0 → 1.7.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/README.md +1 -0
- package/config.example.json +17 -1
- package/dist/cli/args.d.ts +13 -2
- package/dist/cli/args.js +95 -24
- package/dist/cli/commands/accounts.js +45 -17
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.js +9 -2
- package/dist/cli/commands/data/clean.js +32 -9
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/launch/add-root.d.ts +3 -2
- package/dist/cli/commands/launch/add-root.js +11 -10
- package/dist/cli/commands/launch/launch.js +57 -4
- package/dist/cli/commands/launch/prepare.js +3 -1
- package/dist/cli/commands/maintenance/audit.js +1 -1
- package/dist/cli/commands/maintenance/clean.d.ts +1 -1
- package/dist/cli/commands/maintenance/clean.js +17 -3
- package/dist/cli/commands/maintenance/config.d.ts +1 -1
- package/dist/cli/commands/maintenance/config.js +112 -10
- package/dist/cli/commands/maintenance/doctor.d.ts +1 -1
- package/dist/cli/commands/maintenance/doctor.js +2 -4
- package/dist/cli/commands/maintenance/migrate.d.ts +2 -1
- package/dist/cli/commands/maintenance/migrate.js +19 -4
- package/dist/cli/commands/maintenance/sync.js +2 -0
- package/dist/cli/commands/maintenance/update.d.ts +2 -0
- package/dist/cli/commands/maintenance/update.js +27 -4
- package/dist/cli/commands/projects/here.js +12 -7
- package/dist/cli/commands/projects/projects.js +26 -17
- package/dist/cli/commands/registry.js +7 -0
- package/dist/cli/commands/repair/checks/agents.d.ts +2 -0
- package/dist/cli/commands/repair/checks/agents.js +70 -0
- package/dist/cli/commands/repair/checks/common.d.ts +8 -0
- package/dist/cli/commands/repair/checks/common.js +22 -0
- package/dist/cli/commands/repair/checks/data.d.ts +2 -0
- package/dist/cli/commands/repair/checks/data.js +241 -0
- package/dist/cli/commands/repair/checks/index.d.ts +2 -0
- package/dist/cli/commands/repair/checks/index.js +20 -0
- package/dist/cli/commands/repair/checks/install.d.ts +5 -0
- package/dist/cli/commands/repair/checks/install.js +318 -0
- package/dist/cli/commands/repair/checks/machine.d.ts +2 -0
- package/dist/cli/commands/repair/checks/machine.js +232 -0
- package/dist/cli/commands/repair/checks/network.d.ts +6 -0
- package/dist/cli/commands/repair/checks/network.js +60 -0
- package/dist/cli/commands/repair/checks/pc.d.ts +4 -0
- package/dist/cli/commands/repair/checks/pc.js +55 -0
- package/dist/cli/commands/repair/checks/sandbox.d.ts +2 -0
- package/dist/cli/commands/repair/checks/sandbox.js +267 -0
- package/dist/cli/commands/repair/checks/settings.d.ts +2 -0
- package/dist/cli/commands/repair/checks/settings.js +169 -0
- package/dist/cli/commands/repair/checks/vpn.d.ts +2 -0
- package/dist/cli/commands/repair/checks/vpn.js +53 -0
- package/dist/cli/commands/repair/engine.d.ts +32 -0
- package/dist/cli/commands/repair/engine.js +127 -0
- package/dist/cli/commands/repair/env.d.ts +7 -0
- package/dist/cli/commands/repair/env.js +49 -0
- package/dist/cli/commands/repair/index.d.ts +1 -9
- package/dist/cli/commands/repair/index.js +2 -54
- package/dist/cli/commands/repair/log.d.ts +17 -0
- package/dist/cli/commands/repair/log.js +82 -0
- package/dist/cli/commands/repair/printer.d.ts +32 -0
- package/dist/cli/commands/repair/printer.js +132 -0
- package/dist/cli/commands/repair/run.d.ts +33 -0
- package/dist/cli/commands/repair/run.js +133 -0
- package/dist/cli/commands/repair/types.d.ts +97 -9
- package/dist/cli/commands/repair/types.js +11 -7
- package/dist/cli/commands/resume.js +2 -2
- package/dist/cli/commands/sessions/list.js +5 -2
- package/dist/cli/commands/sessions/status.d.ts +2 -0
- package/dist/cli/commands/sessions/status.js +27 -6
- package/dist/cli/commands/setup/index.d.ts +5 -0
- package/dist/cli/commands/setup/index.js +25 -1
- package/dist/cli/commands/storage/index.d.ts +2 -0
- package/dist/cli/commands/storage/index.js +2 -0
- package/dist/cli/commands/storage/offer.d.ts +3 -0
- package/dist/cli/commands/storage/offer.js +85 -0
- package/dist/cli/commands/storage/storage.d.ts +8 -0
- package/dist/cli/commands/storage/storage.js +171 -0
- package/dist/cli/commands/user-config.js +1 -1
- package/dist/cli/commands/vpn.d.ts +4 -0
- package/dist/cli/commands/vpn.js +75 -0
- package/dist/cli/commands/web.d.ts +4 -0
- package/dist/cli/commands/web.js +95 -0
- package/dist/cli/history.js +1 -1
- package/dist/cli/index.js +46 -3
- package/dist/cli/manifest.d.ts +303 -29
- package/dist/cli/manifest.js +173 -43
- package/dist/cli/menu/add-agent.d.ts +47 -0
- package/dist/cli/menu/add-agent.js +168 -0
- package/dist/cli/menu/apps.d.ts +31 -2
- package/dist/cli/menu/apps.js +44 -5
- package/dist/cli/menu/command-fields.d.ts +18 -0
- package/dist/cli/menu/command-fields.js +61 -0
- package/dist/cli/menu/command-form.d.ts +22 -0
- package/dist/cli/menu/command-form.js +169 -46
- package/dist/cli/menu/data-folder.d.ts +18 -0
- package/dist/cli/menu/data-folder.js +99 -0
- package/dist/cli/menu/menu.d.ts +1 -1
- package/dist/cli/menu/menu.js +11 -8
- package/dist/cli/menu/pages/accounts-page.js +55 -24
- package/dist/cli/menu/pages/agents-page.d.ts +66 -0
- package/dist/cli/menu/pages/agents-page.js +338 -0
- package/dist/cli/menu/pages/apps-page.js +1 -2
- package/dist/cli/menu/pages/list-page.d.ts +16 -3
- package/dist/cli/menu/pages/list-page.js +40 -8
- package/dist/cli/menu/pages/maintenance-page.d.ts +9 -0
- package/dist/cli/menu/pages/maintenance-page.js +161 -72
- package/dist/cli/menu/pages/sandbox-page.d.ts +3 -0
- package/dist/cli/menu/pages/sandbox-page.js +132 -43
- package/dist/cli/menu/pages/sessions-page.d.ts +4 -0
- package/dist/cli/menu/pages/sessions-page.js +41 -25
- package/dist/cli/menu/pages/settings-page.d.ts +8 -4
- package/dist/cli/menu/pages/settings-page.js +36 -13
- package/dist/cli/menu/settings/categories.d.ts +2 -0
- package/dist/cli/menu/settings/categories.js +19 -44
- package/dist/cli/menu/settings/collections/collection-editor.d.ts +7 -1
- package/dist/cli/menu/settings/collections/collection-editor.js +12 -8
- package/dist/cli/menu/settings/collections/map-editor.js +5 -1
- package/dist/cli/menu/settings/collections/object-list-editor.js +2 -2
- package/dist/cli/menu/settings/collections/object-map-editor.js +2 -2
- package/dist/cli/menu/settings/collections/string-list-editor.d.ts +11 -1
- package/dist/cli/menu/settings/collections/string-list-editor.js +23 -0
- package/dist/cli/menu/settings/index.d.ts +1 -1
- package/dist/cli/menu/settings/index.js +1 -1
- package/dist/cli/menu/settings/object-editor.d.ts +5 -1
- package/dist/cli/menu/settings/object-editor.js +15 -4
- package/dist/cli/menu/settings/path-kind.d.ts +20 -0
- package/dist/cli/menu/settings/path-kind.js +44 -0
- package/dist/cli/menu/settings/schema-node.d.ts +9 -0
- package/dist/cli/menu/settings/schema-node.js +26 -0
- package/dist/cli/menu/settings/value-editor.d.ts +5 -0
- package/dist/cli/menu/settings/value-editor.js +51 -18
- package/dist/cli/menu/several.js +7 -5
- package/dist/cli/menu/shell.d.ts +37 -10
- package/dist/cli/menu/shell.js +90 -10
- package/dist/cli/menu/vpn-login.d.ts +16 -0
- package/dist/cli/menu/vpn-login.js +66 -0
- package/dist/cli/output/print.d.ts +2 -0
- package/dist/cli/output/print.js +8 -1
- package/dist/cli/services/accounts-service.d.ts +2 -0
- package/dist/cli/services/accounts-service.js +2 -2
- package/dist/cli/services/health-service.d.ts +0 -6
- package/dist/cli/services/health-service.js +5 -42
- package/dist/cli/services/index.d.ts +3 -1
- package/dist/cli/services/index.js +3 -1
- package/dist/cli/services/migrate-service.js +1 -1
- package/dist/cli/services/update-service.d.ts +2 -0
- package/dist/cli/services/update-service.js +13 -6
- package/dist/cli/services/vpn-service.d.ts +28 -0
- package/dist/cli/services/vpn-service.js +46 -0
- package/dist/cli/services/web-service.d.ts +22 -0
- package/dist/cli/services/web-service.js +111 -0
- package/dist/cli/tui/app.d.ts +6 -3
- package/dist/cli/tui/app.js +12 -5
- package/dist/cli/tui/dialogs/path-listing.d.ts +43 -0
- package/dist/cli/tui/dialogs/path-listing.js +127 -0
- package/dist/cli/tui/dialogs/path-picker.d.ts +67 -0
- package/dist/cli/tui/dialogs/path-picker.js +423 -0
- package/dist/cli/tui/dialogs/text-screen.d.ts +6 -0
- package/dist/cli/tui/dialogs/text-screen.js +10 -3
- package/dist/cli/tui/frame.d.ts +7 -10
- package/dist/cli/tui/frame.js +19 -10
- package/dist/cli/tui/index.d.ts +4 -3
- package/dist/cli/tui/index.js +2 -1
- package/dist/cli/tui/list/list-screen.d.ts +14 -2
- package/dist/cli/tui/list/list-screen.js +68 -32
- package/dist/cli/tui/list/list-types.d.ts +8 -4
- package/dist/cli/tui/nav.d.ts +29 -0
- package/dist/cli/tui/nav.js +67 -0
- package/dist/cli/validate.d.ts +1 -1
- package/dist/cli/validate.js +3 -3
- package/dist/cli/version.d.ts +2 -0
- package/dist/cli/version.js +11 -0
- package/dist/core/config/defaults.js +5 -1
- package/dist/core/config/loader.js +12 -2
- package/dist/core/local-config/overrides.js +1 -0
- package/dist/core/prompt.d.ts +19 -0
- package/dist/core/prompt.js +43 -3
- package/dist/core/schema/common.d.ts +6 -0
- package/dist/core/schema/common.js +8 -0
- package/dist/core/schema/config.d.ts +23 -0
- package/dist/core/schema/config.js +10 -1
- package/dist/core/schema/harness.d.ts +1 -0
- package/dist/core/schema/harness.js +8 -2
- package/dist/core/schema/index.d.ts +3 -1
- package/dist/core/schema/index.js +3 -1
- package/dist/core/schema/profile.d.ts +1 -0
- package/dist/core/schema/profile.js +3 -0
- package/dist/core/schema/redact.d.ts +13 -0
- package/dist/core/schema/redact.js +75 -0
- package/dist/core/schema/sandbox.js +1 -0
- package/dist/core/schema/vpn.d.ts +17 -0
- package/dist/core/schema/vpn.js +22 -0
- package/dist/core/schema/web.d.ts +6 -0
- package/dist/core/schema/web.js +14 -0
- package/dist/core/types.d.ts +26 -0
- package/dist/guest/agents/agent-files.d.ts +49 -0
- package/dist/guest/agents/agent-files.js +63 -0
- package/dist/guest/agents/agent-installer.js +2 -9
- package/dist/guest/agents/local-state.d.ts +12 -0
- package/dist/guest/agents/local-state.js +198 -0
- package/dist/guest/agents/sbx-agent.d.ts +2 -0
- package/dist/guest/agents/sbx-agent.js +35 -0
- package/dist/guest/boot/boot.d.ts +4 -0
- package/dist/guest/boot/boot.js +50 -11
- package/dist/guest/daemon/daemon.js +4 -1
- package/dist/guest/daemon/exec.js +2 -1
- package/dist/guest/daemon/idle-shutdown.js +2 -0
- package/dist/guest/daemon/sessions.js +4 -1
- package/dist/guest/entries/agent.d.ts +1 -0
- package/dist/guest/entries/agent.js +10 -0
- package/dist/guest/entries/daemon.js +2 -0
- package/dist/guest/runtime/csc.d.ts +1 -0
- package/dist/guest/runtime/csc.js +1 -0
- package/dist/guest/runtime/secrets.d.ts +12 -0
- package/dist/guest/runtime/secrets.js +63 -0
- package/dist/guest/setup/claude-profile.d.ts +2 -1
- package/dist/guest/setup/claude-profile.js +12 -1
- package/dist/guest/setup/environment.d.ts +6 -0
- package/dist/guest/setup/environment.js +56 -6
- package/dist/guest/setup/path-plan.d.ts +32 -0
- package/dist/guest/setup/path-plan.js +67 -0
- package/dist/guest/setup/shell-path.d.ts +1 -0
- package/dist/guest/setup/shell-path.js +22 -0
- package/dist/guest/toolchains/languages/python.js +1 -1
- package/dist/guest/toolchains/runtimes.js +2 -2
- package/dist/guest/vpn/index.d.ts +1 -0
- package/dist/guest/vpn/index.js +1 -0
- package/dist/guest/vpn/openvpn.d.ts +9 -0
- package/dist/guest/vpn/openvpn.js +47 -0
- package/dist/guest/vpn/tunnel.d.ts +17 -0
- package/dist/guest/vpn/tunnel.js +78 -0
- package/dist/guest/vpn/vpn.d.ts +6 -0
- package/dist/guest/vpn/vpn.js +126 -0
- package/dist/host/channel/attach.d.ts +3 -1
- package/dist/host/channel/attach.js +1 -1
- package/dist/host/channel/channel.d.ts +7 -0
- package/dist/host/channel/channel.js +26 -2
- package/dist/host/health/acl-read.d.ts +17 -0
- package/dist/host/health/acl-read.js +45 -0
- package/dist/host/health/config-backup.d.ts +11 -0
- package/dist/host/health/config-backup.js +73 -0
- package/dist/host/health/index.d.ts +6 -0
- package/dist/host/health/index.js +7 -0
- package/dist/host/health/install-state.d.ts +33 -0
- package/dist/host/health/install-state.js +110 -0
- package/dist/host/health/path-copies.d.ts +32 -0
- package/dist/host/health/path-copies.js +82 -0
- package/dist/host/health/stale.d.ts +45 -0
- package/dist/host/health/stale.js +120 -0
- package/dist/host/health/system.d.ts +37 -0
- package/dist/host/health/system.js +87 -0
- package/dist/host/install/copies.d.ts +13 -0
- package/dist/host/install/copies.js +63 -0
- package/dist/host/install/index.d.ts +1 -0
- package/dist/host/install/index.js +1 -0
- package/dist/host/launch/generate.js +25 -1
- package/dist/host/launch/session-file.js +4 -1
- package/dist/host/launch/stage.js +1 -1
- package/dist/host/migrate/backup.js +3 -0
- package/dist/host/migrate/migrations/config-file.d.ts +2 -0
- package/dist/host/migrate/migrations/config-file.js +7 -0
- package/dist/host/migrate/migrations/follow-machine-storage.js +9 -1
- package/dist/host/migrate/migrations/pin-storage-root.d.ts +4 -0
- package/dist/host/migrate/migrations/pin-storage-root.js +46 -0
- package/dist/host/migrate/migrations/unpin-config-defaults.js +4 -1
- package/dist/host/migrate/registry.js +2 -1
- package/dist/host/profile/accounts.d.ts +25 -1
- package/dist/host/profile/accounts.js +96 -13
- package/dist/host/profile/agent-accounts.d.ts +5 -1
- package/dist/host/profile/agent-accounts.js +35 -5
- package/dist/host/profile/index.d.ts +2 -1
- package/dist/host/profile/index.js +1 -0
- package/dist/host/profile/plugin-share.d.ts +26 -0
- package/dist/host/profile/plugin-share.js +146 -0
- package/dist/host/projects/join.d.ts +7 -1
- package/dist/host/projects/join.js +21 -4
- package/dist/host/projects/registry.d.ts +16 -10
- package/dist/host/projects/registry.js +74 -6
- package/dist/host/sandbox/platform.d.ts +2 -0
- package/dist/host/sandbox/platform.js +21 -2
- package/dist/host/secrets/index.d.ts +2 -0
- package/dist/host/secrets/index.js +2 -0
- package/dist/host/secrets/launch-secrets.d.ts +17 -0
- package/dist/host/secrets/launch-secrets.js +93 -0
- package/dist/host/secrets/secret-store.d.ts +25 -0
- package/dist/host/secrets/secret-store.js +89 -0
- package/dist/host/sharing/acl.d.ts +16 -2
- package/dist/host/sharing/acl.js +35 -10
- package/dist/host/sharing/current.js +11 -2
- package/dist/host/sharing/doctor.d.ts +2 -0
- package/dist/host/sharing/doctor.js +44 -0
- package/dist/host/sharing/group-access.d.ts +6 -0
- package/dist/host/sharing/group-access.js +24 -0
- package/dist/host/sharing/index.d.ts +2 -1
- package/dist/host/sharing/index.js +2 -1
- package/dist/host/sharing/lifecycle.d.ts +8 -2
- package/dist/host/sharing/lifecycle.js +16 -7
- package/dist/host/storage/cleanup.d.ts +2 -0
- package/dist/host/storage/cleanup.js +2 -1
- package/dist/host/storage/history.d.ts +21 -0
- package/dist/host/storage/history.js +49 -0
- package/dist/host/storage/index.d.ts +4 -0
- package/dist/host/storage/index.js +4 -0
- package/dist/host/storage/move.d.ts +95 -0
- package/dist/host/storage/move.js +384 -0
- package/dist/host/storage/offer.d.ts +11 -0
- package/dist/host/storage/offer.js +36 -0
- package/dist/host/storage/root.d.ts +18 -0
- package/dist/host/storage/root.js +77 -0
- package/dist/host/tools/windows-terminal.d.ts +2 -0
- package/dist/host/tools/windows-terminal.js +23 -5
- package/dist/host/update/index.d.ts +1 -1
- package/dist/host/update/index.js +1 -1
- package/dist/host/update/notice.d.ts +2 -0
- package/dist/host/update/notice.js +13 -1
- package/dist/host/update/update-state.d.ts +6 -0
- package/dist/host/update/update-state.js +2 -0
- package/dist/host/update/updater.d.ts +19 -0
- package/dist/host/update/updater.js +88 -12
- package/dist/host/vpn/index.d.ts +4 -0
- package/dist/host/vpn/index.js +4 -0
- package/dist/host/vpn/login.d.ts +24 -0
- package/dist/host/vpn/login.js +79 -0
- package/dist/host/vpn/nordvpn.d.ts +21 -0
- package/dist/host/vpn/nordvpn.js +77 -0
- package/dist/host/vpn/prepare.d.ts +17 -0
- package/dist/host/vpn/prepare.js +77 -0
- package/dist/host/vpn/status.d.ts +12 -0
- package/dist/host/vpn/status.js +53 -0
- package/dist/host/web/auth.d.ts +38 -0
- package/dist/host/web/auth.js +96 -0
- package/dist/host/web/backend.d.ts +14 -0
- package/dist/host/web/backend.js +1 -0
- package/dist/host/web/bridge.d.ts +27 -0
- package/dist/host/web/bridge.js +144 -0
- package/dist/host/web/browser.d.ts +1 -0
- package/dist/host/web/browser.js +10 -0
- package/dist/host/web/control.d.ts +17 -0
- package/dist/host/web/control.js +67 -0
- package/dist/host/web/index.d.ts +9 -0
- package/dist/host/web/index.js +8 -0
- package/dist/host/web/runner.d.ts +14 -0
- package/dist/host/web/runner.js +45 -0
- package/dist/host/web/server.d.ts +40 -0
- package/dist/host/web/server.js +218 -0
- package/dist/host/web/state.d.ts +20 -0
- package/dist/host/web/state.js +41 -0
- package/dist/host/web/static-files.d.ts +13 -0
- package/dist/host/web/static-files.js +57 -0
- package/dist/runtime/agent.js +27614 -0
- package/dist/runtime/daemon.js +1012 -618
- package/dist/runtime/db.js +236 -106
- package/dist/runtime/main.js +1093 -250
- package/dist/runtime/netproxy.js +102 -3
- package/dist/runtime/view.js +102 -3
- package/dist/selftest/accounts.test.js +40 -0
- package/dist/selftest/agent-paths.test.d.ts +2 -0
- package/dist/selftest/agent-paths.test.js +115 -0
- package/dist/selftest/channel.test.js +5 -0
- package/dist/selftest/cli.test.js +34 -4
- package/dist/selftest/credentials.test.d.ts +2 -0
- package/dist/selftest/credentials.test.js +198 -0
- package/dist/selftest/generate.test.js +1 -1
- package/dist/selftest/health.test.d.ts +2 -0
- package/dist/selftest/health.test.js +470 -0
- package/dist/selftest/host-sim.test.js +2 -0
- package/dist/selftest/index.js +19 -0
- package/dist/selftest/layout.test.js +2 -0
- package/dist/selftest/menu-screens.d.ts +7 -0
- package/dist/selftest/menu-screens.js +65 -16
- package/dist/selftest/menu.test.js +574 -21
- package/dist/selftest/migrate.test.js +1 -1
- package/dist/selftest/personalization.test.js +3 -1
- package/dist/selftest/projects.test.js +39 -1
- package/dist/selftest/shared-use.test.js +64 -2
- package/dist/selftest/sharing.test.js +50 -1
- package/dist/selftest/storage.test.d.ts +2 -0
- package/dist/selftest/storage.test.js +363 -0
- package/dist/selftest/support/fixtures.d.ts +14 -0
- package/dist/selftest/support/releases.js +1 -1
- package/dist/selftest/toolchains.test.js +21 -0
- package/dist/selftest/update-service.test.js +87 -3
- package/dist/selftest/vpn.test.d.ts +2 -0
- package/dist/selftest/vpn.test.js +279 -0
- package/dist/selftest/web.test.d.ts +2 -0
- package/dist/selftest/web.test.js +304 -0
- package/dist/shared/apps/catalogue.js +31 -0
- package/dist/shared/channel/index.d.ts +1 -0
- package/dist/shared/channel/index.js +1 -0
- package/dist/shared/channel/run-dir.d.ts +6 -1
- package/dist/shared/channel/run-dir.js +12 -1
- package/dist/shared/channel/schema.d.ts +19 -0
- package/dist/shared/channel/schema.js +11 -0
- package/dist/shared/channel/secrets.d.ts +28 -0
- package/dist/shared/channel/secrets.js +44 -0
- package/dist/shared/vpn/download.d.ts +13 -0
- package/dist/shared/vpn/download.js +14 -0
- package/dist/shared/vpn/kill-switch.d.ts +18 -0
- package/dist/shared/vpn/kill-switch.js +81 -0
- package/dist/shared/vpn/ovpn.d.ts +23 -0
- package/dist/shared/vpn/ovpn.js +244 -0
- package/dist/shared/web/index.d.ts +1 -0
- package/dist/shared/web/index.js +1 -0
- package/dist/shared/web/protocol.d.ts +61 -0
- package/dist/shared/web/protocol.js +35 -0
- package/dist/sync/sync-cycle.js +5 -1
- package/dist/sync/sync-state.d.ts +1 -0
- package/dist/sync/sync-state.js +1 -0
- package/dist/sync/watcher.js +10 -0
- package/dist/web/index.html +13 -0
- package/dist/web/main-CXESL347.js +45 -0
- package/dist/web/main-VLR7DVQ4.css +1 -0
- package/native/csharp/FolderSecurity.cs +29 -0
- package/native/scripts/protect-data.ps1 +29 -0
- package/native/scripts/read-folder-sddl.ps1 +10 -0
- package/native/scripts/set-folder-access.ps1 +49 -7
- package/node_modules/ws/LICENSE +20 -0
- package/node_modules/ws/README.md +548 -0
- package/node_modules/ws/browser.js +8 -0
- package/node_modules/ws/index.js +22 -0
- package/node_modules/ws/lib/buffer-util.js +131 -0
- package/node_modules/ws/lib/constants.js +19 -0
- package/node_modules/ws/lib/event-target.js +292 -0
- package/node_modules/ws/lib/extension.js +203 -0
- package/node_modules/ws/lib/limiter.js +55 -0
- package/node_modules/ws/lib/permessage-deflate.js +530 -0
- package/node_modules/ws/lib/receiver.js +743 -0
- package/node_modules/ws/lib/sender.js +607 -0
- package/node_modules/ws/lib/stream.js +161 -0
- package/node_modules/ws/lib/subprotocol.js +62 -0
- package/node_modules/ws/lib/validation.js +152 -0
- package/node_modules/ws/lib/websocket-server.js +562 -0
- package/node_modules/ws/lib/websocket.js +1421 -0
- package/node_modules/ws/package.json +74 -0
- package/node_modules/ws/wrapper.mjs +21 -0
- package/package.json +15 -5
- package/sandbox/csharp/EnvBroadcast.cs +33 -0
- package/sandbox/csharp/PathSync.cs +90 -0
- package/sandbox/scripts/install-shell-path.ps1 +73 -0
- package/sandbox/scripts/set-machine-environment.ps1 +37 -4
- package/schemas/config.schema.json +79 -4
- package/schemas/sandbox-config.schema.json +14 -1
- package/dist/cli/commands/repair/checks.d.ts +0 -2
- package/dist/cli/commands/repair/checks.js +0 -246
- package/dist/cli/menu/pages/start-page.d.ts +0 -43
- package/dist/cli/menu/pages/start-page.js +0 -192
- package/dist/cli/tui/tab-bar.d.ts +0 -9
- package/dist/cli/tui/tab-bar.js +0 -33
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// Install: how this program was installed, and whether the pieces a managed install runs from are in one piece (the
|
|
2
|
+
// version and Node pointers, the shims, the PATH entry, the update task, the record). Fixes move a pointer, rewrite
|
|
3
|
+
// shims or add the user PATH entry; they never delete a version.
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileExists } from '../../../../core/util/index.js';
|
|
7
|
+
import { editUserPath } from '../../../../host/agent-commands/index.js';
|
|
8
|
+
import { HIGH_INTEGRITY_SID, binsOfPackage, currentPathext, fileOnDisk, findCommandCopies, inspectPointers, ownBinDir, pathHas, repairPointers, sameFolder, shimProblems, } from '../../../../host/health/index.js';
|
|
9
|
+
import { UpdateTask, writeShims } from '../../../../host/install/index.js';
|
|
10
|
+
import { assertTestWritable, refuseInSelfTest } from '../../../../host/test-guard.js';
|
|
11
|
+
import { globalPackages } from '../finders.js';
|
|
12
|
+
import { ok, plural } from './common.js';
|
|
13
|
+
const UNINSTALL = '& ([scriptblock]::Create((irm https://github.com/JoshDiDuca/windows-development-sandbox/releases/latest/download/install.ps1))) -Uninstall -Scope ';
|
|
14
|
+
/** The exact way to get rid of one copy (nothing here runs it: doctor only prints it). */
|
|
15
|
+
export function removalCommand(copy) {
|
|
16
|
+
switch (copy.kind) {
|
|
17
|
+
case 'managed-machine':
|
|
18
|
+
return 'in an admin PowerShell: ' + UNINSTALL + 'AllUsers';
|
|
19
|
+
case 'managed-user':
|
|
20
|
+
return 'in PowerShell: ' + UNINSTALL + 'CurrentUser';
|
|
21
|
+
case 'npm': {
|
|
22
|
+
const current = fileOnDisk(path.join(copy.dir, 'node_modules', 'windows-development-sandbox', 'package.json'));
|
|
23
|
+
return 'npm uninstall -g ' + (current ? 'windows-development-sandbox' : 'agent-sandbox');
|
|
24
|
+
}
|
|
25
|
+
case 'old-scripts': {
|
|
26
|
+
const root = path.basename(copy.dir).toLowerCase() === 'bin' ? path.dirname(copy.dir) : copy.dir;
|
|
27
|
+
return 'Remove-Item -Recurse -Force "' + root + '" (and take ' + copy.dir + ' off your PATH)';
|
|
28
|
+
}
|
|
29
|
+
default:
|
|
30
|
+
return 'delete ' + copy.files.join(', ') + ' in ' + copy.dir + ', or take that folder off the PATH';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const KIND_NAMES = {
|
|
34
|
+
'managed-machine': 'the install for everyone',
|
|
35
|
+
'managed-user': 'the install for just you',
|
|
36
|
+
npm: 'an npm copy',
|
|
37
|
+
'old-scripts': 'an old Scripts\\agent-sandbox copy',
|
|
38
|
+
other: 'a copy of unknown origin',
|
|
39
|
+
};
|
|
40
|
+
const managed = (env) => env.layout !== null;
|
|
41
|
+
const machine = (env) => env.layout?.scope === 'machine';
|
|
42
|
+
/** The commands of the version the pointers name, else of the one running now. */
|
|
43
|
+
function currentBins(env) {
|
|
44
|
+
const layout = env.layout;
|
|
45
|
+
if (!layout)
|
|
46
|
+
return null;
|
|
47
|
+
const active = layout.activeVersion();
|
|
48
|
+
return (active ? binsOfPackage(layout.packageDir(active)) : null) ?? binsOfPackage(env.ctx.packageRoot);
|
|
49
|
+
}
|
|
50
|
+
export const INSTALL_CHECKS = [
|
|
51
|
+
{
|
|
52
|
+
id: 'install-kind',
|
|
53
|
+
group: 'Install',
|
|
54
|
+
name: 'Install type',
|
|
55
|
+
run: (env) => {
|
|
56
|
+
const layout = env.layout;
|
|
57
|
+
if (!layout)
|
|
58
|
+
return ok('npm global install (update it with npm; there are no automatic updates)');
|
|
59
|
+
const who = layout.scope === 'machine' ? 'for everyone on this PC' : 'for you';
|
|
60
|
+
return ok('managed install ' + who + ' in ' + layout.root + ', version ' + (layout.activeVersion() ?? 'unknown'));
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'install-record',
|
|
65
|
+
group: 'Install',
|
|
66
|
+
name: 'Install record',
|
|
67
|
+
applies: managed,
|
|
68
|
+
run: (env) => {
|
|
69
|
+
if (env.record)
|
|
70
|
+
return ok('install.json: ' + env.record.scope + ' install, automatic updates ' + (env.record.autoUpdate ? 'on' : 'off'));
|
|
71
|
+
return {
|
|
72
|
+
status: 'warn',
|
|
73
|
+
detail: 'install.json is missing or cannot be read',
|
|
74
|
+
means: 'Updates and sharing cannot tell how this was installed, so they act as if automatic updates are off.',
|
|
75
|
+
fix: 'Run the installer again over this install (it writes the record and keeps your data).',
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'install-pointers',
|
|
81
|
+
group: 'Install',
|
|
82
|
+
name: 'Active version',
|
|
83
|
+
applies: managed,
|
|
84
|
+
run: (env) => {
|
|
85
|
+
const layout = env.layout;
|
|
86
|
+
if (!layout)
|
|
87
|
+
return ok('');
|
|
88
|
+
const state = inspectPointers(layout);
|
|
89
|
+
if (!state.problems.length)
|
|
90
|
+
return ok('version ' + state.activeVersion + ' with Node ' + state.activeNode);
|
|
91
|
+
const base = {
|
|
92
|
+
status: 'needs-you',
|
|
93
|
+
detail: state.problems.join('; '),
|
|
94
|
+
means: 'The sandbox command cannot start until both pointers name an installed version and Node.',
|
|
95
|
+
};
|
|
96
|
+
if (!state.want)
|
|
97
|
+
return {
|
|
98
|
+
...base,
|
|
99
|
+
fix: 'Nothing complete is installed in ' + layout.root + '. Run the installer again.',
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
...base,
|
|
103
|
+
plan: 'point active-version at ' + state.want.version + ' and active-node at ' + state.want.node + ' (installed)',
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
fix: (env) => {
|
|
107
|
+
if (!env.layout)
|
|
108
|
+
throw new Error('not a managed install');
|
|
109
|
+
assertTestWritable(env.layout.root);
|
|
110
|
+
return { done: 'pointed at ' + repairPointers(env.layout) };
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 'install-shims',
|
|
115
|
+
group: 'Install',
|
|
116
|
+
name: 'Commands (shims)',
|
|
117
|
+
applies: managed,
|
|
118
|
+
run: (env) => {
|
|
119
|
+
const layout = env.layout;
|
|
120
|
+
const bins = currentBins(env);
|
|
121
|
+
if (!layout || !bins)
|
|
122
|
+
return { status: 'skipped', detail: 'the package.json of the active version cannot be read' };
|
|
123
|
+
const problems = shimProblems(layout, bins);
|
|
124
|
+
const count = Object.keys(bins).length;
|
|
125
|
+
if (!problems.missing.length && !problems.different.length)
|
|
126
|
+
return ok(plural(count, 'command') + ' in ' + layout.binDir + ' read the active version');
|
|
127
|
+
const bad = [
|
|
128
|
+
...problems.missing.map((f) => f + ' (missing)'),
|
|
129
|
+
...problems.different.map((f) => f + ' (out of date)'),
|
|
130
|
+
];
|
|
131
|
+
return {
|
|
132
|
+
status: 'needs-you',
|
|
133
|
+
detail: bad.slice(0, 4).join(', ') + (bad.length > 4 ? ' and ' + (bad.length - 4) + ' more' : ''),
|
|
134
|
+
means: 'Typing sandbox in a terminal may fail or run the wrong version.',
|
|
135
|
+
plan: 'rewrite ' + plural(bad.length, 'command file') + ' in ' + layout.binDir,
|
|
136
|
+
lines: bad,
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
fix: (env) => {
|
|
140
|
+
const bins = currentBins(env);
|
|
141
|
+
if (!env.layout || !bins)
|
|
142
|
+
throw new Error('the package.json of the active version cannot be read');
|
|
143
|
+
assertTestWritable(env.layout.binDir);
|
|
144
|
+
writeShims(env.layout, bins);
|
|
145
|
+
return { done: 'rewrote the command files for ' + Object.keys(bins).join(', ') };
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 'install-path',
|
|
150
|
+
group: 'Install',
|
|
151
|
+
name: 'PATH',
|
|
152
|
+
applies: managed,
|
|
153
|
+
timeoutMs: 40_000,
|
|
154
|
+
run: (env) => {
|
|
155
|
+
const layout = env.layout;
|
|
156
|
+
if (!layout)
|
|
157
|
+
return ok('');
|
|
158
|
+
const scope = layout.scope === 'machine' ? 'machine' : 'user';
|
|
159
|
+
const where = scope === 'machine' ? 'the PATH of this PC' : 'your PATH';
|
|
160
|
+
const own = env.system.registryPath(scope);
|
|
161
|
+
if (own === null)
|
|
162
|
+
return { status: 'skipped', detail: 'could not read ' + where };
|
|
163
|
+
if (pathHas(own, layout.binDir))
|
|
164
|
+
return ok(layout.binDir + ' is on ' + where);
|
|
165
|
+
const other = env.system.registryPath(scope === 'machine' ? 'user' : 'machine');
|
|
166
|
+
const base = {
|
|
167
|
+
status: 'needs-you',
|
|
168
|
+
detail: layout.binDir + ' is not on ' + where + (pathHas(other, layout.binDir) ? ' (only on the other one)' : ''),
|
|
169
|
+
means: 'New terminals will not find the sandbox command.',
|
|
170
|
+
};
|
|
171
|
+
if (scope === 'user')
|
|
172
|
+
return { ...base, plan: 'add ' + layout.binDir + ' to your PATH' };
|
|
173
|
+
return {
|
|
174
|
+
...base,
|
|
175
|
+
fix: 'Run the installer again in an admin PowerShell (it adds the folder to the PATH of this PC).',
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
fix: (env) => {
|
|
179
|
+
if (!env.layout)
|
|
180
|
+
throw new Error('not a managed install');
|
|
181
|
+
editUserPath(env.layout.binDir, true, env.storageRoot);
|
|
182
|
+
return { done: 'added ' + env.layout.binDir + ' to your PATH (open a new terminal to use it)' };
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 'install-copies',
|
|
187
|
+
group: 'Install',
|
|
188
|
+
name: 'Copies on the PATH',
|
|
189
|
+
timeoutMs: 40_000,
|
|
190
|
+
run: (env) => {
|
|
191
|
+
const machinePath = env.system.registryPath('machine');
|
|
192
|
+
const userPath = env.system.registryPath('user');
|
|
193
|
+
const copies = findCommandCopies({
|
|
194
|
+
machinePath: machinePath ?? (userPath === null ? (process.env.Path ?? null) : null),
|
|
195
|
+
userPath,
|
|
196
|
+
pathext: currentPathext(),
|
|
197
|
+
programFiles: process.env.ProgramFiles ?? null,
|
|
198
|
+
localAppData: process.env.LOCALAPPDATA ?? null,
|
|
199
|
+
exists: fileOnDisk,
|
|
200
|
+
});
|
|
201
|
+
if (!copies.length)
|
|
202
|
+
return ok('no sandbox command is on the PATH of a new terminal');
|
|
203
|
+
const runs = copies.find((c) => c.files.some((f) => f.startsWith('sandbox.'))) ?? copies[0];
|
|
204
|
+
const own = ownBinDir(env.ctx.packageRoot, env.layout?.binDir ?? null);
|
|
205
|
+
const keep = copies.find((c) => c.kind === 'managed-machine' || c.kind === 'managed-user') ?? runs;
|
|
206
|
+
if (copies.length === 1 && (!own || sameFolder(own, runs.dir)))
|
|
207
|
+
return ok('one copy: ' + runs.dir + ' (' + KIND_NAMES[runs.kind] + ')');
|
|
208
|
+
const hidden = copies.filter((c) => c !== keep);
|
|
209
|
+
const wrong = keep !== runs;
|
|
210
|
+
return {
|
|
211
|
+
status: wrong || (own !== null && !sameFolder(own, runs.dir)) ? 'needs-you' : 'warn',
|
|
212
|
+
detail: wrong
|
|
213
|
+
? 'typing sandbox runs ' + runs.dir + ' (' + KIND_NAMES[runs.kind] + '), not ' + keep.dir
|
|
214
|
+
: copies.length + ' copies are on the PATH; ' + runs.dir + ' runs (' + KIND_NAMES[runs.kind] + ')',
|
|
215
|
+
means: wrong
|
|
216
|
+
? 'The install you update is hidden, so its fixes never reach you, and sharing with other users may not work from this copy.'
|
|
217
|
+
: 'The others are never used, and they may be the ones an old shortcut or script starts.',
|
|
218
|
+
fix: 'Remove the copies you do not want (repair never deletes them; run "Get-Command sandbox -All" to list them):',
|
|
219
|
+
lines: hidden.map((c) => c.dir + ': ' + removalCommand(c)),
|
|
220
|
+
};
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: 'install-task',
|
|
225
|
+
group: 'Install',
|
|
226
|
+
name: 'Automatic updates',
|
|
227
|
+
applies: machine,
|
|
228
|
+
timeoutMs: 40_000,
|
|
229
|
+
run: (env) => {
|
|
230
|
+
const wanted = env.record?.autoUpdate ?? false;
|
|
231
|
+
const has = env.system.updateTaskExists();
|
|
232
|
+
if (has === null)
|
|
233
|
+
return { status: 'skipped', detail: 'could not ask Windows about the update task' };
|
|
234
|
+
if (has === wanted)
|
|
235
|
+
return ok(wanted ? 'on, and the scheduled task is there' : 'off, and no scheduled task is left');
|
|
236
|
+
const admin = env.system.tokenHasGroup(HIGH_INTEGRITY_SID) === true;
|
|
237
|
+
const command = 'sandbox update --auto ' + (wanted ? 'on' : 'off');
|
|
238
|
+
const base = {
|
|
239
|
+
status: 'needs-you',
|
|
240
|
+
detail: wanted
|
|
241
|
+
? 'automatic updates are on but the scheduled task \\WindowsDevelopmentSandbox\\Update is missing'
|
|
242
|
+
: 'automatic updates are off but the scheduled task is still there',
|
|
243
|
+
means: wanted ? 'No update is installed by itself.' : 'The task keeps trying to update.',
|
|
244
|
+
};
|
|
245
|
+
return admin
|
|
246
|
+
? { ...base, plan: wanted ? 'create the update task' : 'remove the update task' }
|
|
247
|
+
: { ...base, fix: 'Changing it needs admin rights. In an admin terminal run: ' + command };
|
|
248
|
+
},
|
|
249
|
+
fix: (env) => {
|
|
250
|
+
if (!env.layout)
|
|
251
|
+
throw new Error('not a managed install');
|
|
252
|
+
refuseInSelfTest('change scheduled tasks');
|
|
253
|
+
const task = new UpdateTask(env.layout);
|
|
254
|
+
if (env.record?.autoUpdate) {
|
|
255
|
+
task.register();
|
|
256
|
+
return { done: 'created the update task' };
|
|
257
|
+
}
|
|
258
|
+
task.remove();
|
|
259
|
+
return { done: 'removed the update task' };
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: 'install-user-leftover',
|
|
264
|
+
group: 'Install',
|
|
265
|
+
name: 'Install for just you',
|
|
266
|
+
applies: (env) => machine(env) && env.userInstallRoot !== null,
|
|
267
|
+
run: (env) => {
|
|
268
|
+
const root = env.userInstallRoot;
|
|
269
|
+
if (!root || !fileExists(path.join(root, 'active-version')))
|
|
270
|
+
return ok('no second install for just you next to this one');
|
|
271
|
+
return {
|
|
272
|
+
status: 'warn',
|
|
273
|
+
detail: 'an install for just you is still in ' + root,
|
|
274
|
+
means: 'Both are on your PATH; whichever comes first runs, and its updates differ from the one for everyone.',
|
|
275
|
+
fix: 'Remove it in PowerShell (your data stays): ' + UNINSTALL + 'CurrentUser',
|
|
276
|
+
};
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: 'install-old-npm',
|
|
281
|
+
group: 'Install',
|
|
282
|
+
name: 'npm packages',
|
|
283
|
+
timeoutMs: 90_000,
|
|
284
|
+
run: (env) => {
|
|
285
|
+
const npmCli = path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
|
286
|
+
if (!fileExists(npmCli))
|
|
287
|
+
return { status: 'skipped', detail: 'npm not found next to this Node (' + npmCli + ')' };
|
|
288
|
+
// cwd = Node's own folder: npm reads .npmrc from the current folder, which could be a sandbox-writable workspace.
|
|
289
|
+
const result = spawnSync(process.execPath, [npmCli, 'ls', '-g', '--json', '--depth=0'], {
|
|
290
|
+
cwd: path.dirname(process.execPath),
|
|
291
|
+
encoding: 'utf8',
|
|
292
|
+
windowsHide: true,
|
|
293
|
+
timeout: 60000,
|
|
294
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
295
|
+
});
|
|
296
|
+
const names = globalPackages(result.stdout ?? '');
|
|
297
|
+
if (!names.length)
|
|
298
|
+
return { status: 'skipped', detail: 'could not read the global npm packages' };
|
|
299
|
+
if (names.includes('agent-sandbox') && names.includes('windows-development-sandbox'))
|
|
300
|
+
return {
|
|
301
|
+
status: 'needs-you',
|
|
302
|
+
detail: 'the old agent-sandbox package is installed next to windows-development-sandbox',
|
|
303
|
+
means: 'Their commands clash, and the one first on PATH runs.',
|
|
304
|
+
fix: 'Run: npm uninstall -g agent-sandbox',
|
|
305
|
+
};
|
|
306
|
+
if (managed(env) && names.includes('windows-development-sandbox'))
|
|
307
|
+
return {
|
|
308
|
+
status: 'warn',
|
|
309
|
+
detail: 'an npm global copy of windows-development-sandbox is installed next to the managed install',
|
|
310
|
+
means: 'Both are on PATH; whichever comes first runs, and only the managed one updates itself.',
|
|
311
|
+
fix: 'Run: npm uninstall -g windows-development-sandbox',
|
|
312
|
+
};
|
|
313
|
+
return ok(names.includes('agent-sandbox')
|
|
314
|
+
? 'agent-sandbox installed (the old name; fine on its own)'
|
|
315
|
+
: 'no old agent-sandbox package');
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
];
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// All-users install: can this user read the settings for the PC, is this user in the sharing group, is the data folder
|
|
2
|
+
// private, are the group's permissions gone when nothing is shared, and are there records of sandboxes that are gone.
|
|
3
|
+
// Only for an install in Program Files; every other install skips these.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { errMsg, isInsideOrEqual, isLink } from '../../../../core/util/index.js';
|
|
7
|
+
import { SHARING_GROUP, groupEntries, parseIcacls, privacyProblems, sharedFolders, staleActiveRecords, } from '../../../../host/health/index.js';
|
|
8
|
+
import { ActiveRecords, applyAcl, protectPrivateFolder, sharingAclPlan, currentUserName, } from '../../../../host/sharing/index.js';
|
|
9
|
+
import { holdsData, storageOf } from '../../../../host/storage/index.js';
|
|
10
|
+
import { ok, plural, sameUser } from './common.js';
|
|
11
|
+
const machine = (env) => env.layout?.scope === 'machine';
|
|
12
|
+
const usersDir = (env) => path.join(env.machineHome, 'users');
|
|
13
|
+
const records = (env) => new ActiveRecords(path.join(env.machineHome, 'active'));
|
|
14
|
+
/** The per-user folder under users\ that holds the storage root, or null when the root is somewhere else. */
|
|
15
|
+
function privateFolder(env) {
|
|
16
|
+
const users = path.resolve(usersDir(env));
|
|
17
|
+
const root = path.resolve(env.storageRoot);
|
|
18
|
+
if (!isInsideOrEqual(users, root) || root.toLowerCase() === users.toLowerCase())
|
|
19
|
+
return null;
|
|
20
|
+
return path.join(users, path.relative(users, root).split(path.sep)[0]);
|
|
21
|
+
}
|
|
22
|
+
/** Does this user have a shared sandbox running (their record says shared, and Windows says it runs)? */
|
|
23
|
+
function sharedRecord(env) {
|
|
24
|
+
return (env.running &&
|
|
25
|
+
records(env)
|
|
26
|
+
.readAll()
|
|
27
|
+
.some((r) => r.shared && r.dataPath.toLowerCase() === env.dataPath.toLowerCase()));
|
|
28
|
+
}
|
|
29
|
+
function icaclsOf(env, dir) {
|
|
30
|
+
const text = env.system.icacls(dir);
|
|
31
|
+
return text === null ? null : parseIcacls(text, dir);
|
|
32
|
+
}
|
|
33
|
+
export const MACHINE_CHECKS = [
|
|
34
|
+
{
|
|
35
|
+
id: 'machine-config',
|
|
36
|
+
group: 'Install',
|
|
37
|
+
name: 'Settings for this PC',
|
|
38
|
+
applies: machine,
|
|
39
|
+
run: (env) => {
|
|
40
|
+
const file = path.join(env.machineHome, 'config.json');
|
|
41
|
+
try {
|
|
42
|
+
fs.accessSync(file, fs.constants.R_OK);
|
|
43
|
+
return ok(file + ' is readable');
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
const code = e.code;
|
|
47
|
+
if (code === 'ENOENT' || code === 'ENOTDIR')
|
|
48
|
+
return ok('no ' + file + ' (the built-in defaults apply)');
|
|
49
|
+
return {
|
|
50
|
+
status: 'needs-you',
|
|
51
|
+
detail: file + ' cannot be read (' + errMsg(e) + ')',
|
|
52
|
+
means: 'Without it your settings for this PC (and the shared defaults) are ignored or refused.',
|
|
53
|
+
fix: 'Sign out of Windows and in again if you were just added to the group "' +
|
|
54
|
+
SHARING_GROUP +
|
|
55
|
+
'"; otherwise ask an administrator to let that group read the file.',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'machine-group',
|
|
62
|
+
group: 'Install',
|
|
63
|
+
name: 'Sharing group',
|
|
64
|
+
applies: machine,
|
|
65
|
+
timeoutMs: 30_000,
|
|
66
|
+
run: (env) => {
|
|
67
|
+
const members = env.system.groupMembers();
|
|
68
|
+
if (members === null)
|
|
69
|
+
return { status: 'skipped', detail: 'could not read the group "' + SHARING_GROUP + '"' };
|
|
70
|
+
const user = currentUserName();
|
|
71
|
+
if (!members.some((m) => sameUser(m, user)))
|
|
72
|
+
return {
|
|
73
|
+
status: 'needs-you',
|
|
74
|
+
detail: user + ' is not in the group "' + SHARING_GROUP + '"',
|
|
75
|
+
means: 'You cannot read the settings for this PC or use a sandbox someone shares.',
|
|
76
|
+
fix: 'Ask an administrator, or in an admin terminal run: net localgroup "' +
|
|
77
|
+
SHARING_GROUP +
|
|
78
|
+
'" ' +
|
|
79
|
+
user +
|
|
80
|
+
' /add (then sign out and in)',
|
|
81
|
+
};
|
|
82
|
+
const sid = env.record?.groupSid;
|
|
83
|
+
if (sid && env.system.tokenHasGroup(sid) === false)
|
|
84
|
+
return {
|
|
85
|
+
status: 'needs-you',
|
|
86
|
+
detail: user + ' is in the group, but this session was started before that',
|
|
87
|
+
means: 'Windows only counts group membership after you sign in again.',
|
|
88
|
+
fix: 'Sign out of Windows and in again.',
|
|
89
|
+
};
|
|
90
|
+
return ok(user + ' is in the group "' + SHARING_GROUP + '"');
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'machine-data-private',
|
|
95
|
+
group: 'Data folder',
|
|
96
|
+
name: 'Private data folder',
|
|
97
|
+
applies: machine,
|
|
98
|
+
timeoutMs: 30_000,
|
|
99
|
+
run: (env) => {
|
|
100
|
+
const dir = privateFolder(env);
|
|
101
|
+
if (!dir)
|
|
102
|
+
return ok(env.storageRoot + ' is not under ' + usersDir(env) + ' (your own choice; not shared)');
|
|
103
|
+
if (!fs.existsSync(dir))
|
|
104
|
+
return ok(dir + ' is not created yet');
|
|
105
|
+
if (isLink(dir))
|
|
106
|
+
return {
|
|
107
|
+
status: 'needs-you',
|
|
108
|
+
detail: dir + ' is a link',
|
|
109
|
+
means: 'It is refused: a link could lead elsewhere.',
|
|
110
|
+
fix: 'Remove the link, or point storage.root at a real folder (sandbox storage move).',
|
|
111
|
+
};
|
|
112
|
+
const entries = icaclsOf(env, dir);
|
|
113
|
+
if (!entries)
|
|
114
|
+
return { status: 'skipped', detail: 'could not read the permissions of ' + dir };
|
|
115
|
+
const bad = privacyProblems(entries, SHARING_GROUP);
|
|
116
|
+
if (!bad.length)
|
|
117
|
+
return ok(dir + ' is private to you');
|
|
118
|
+
return {
|
|
119
|
+
status: 'needs-you',
|
|
120
|
+
detail: dir + ' can also be read by: ' + bad.join(', '),
|
|
121
|
+
means: 'Your saved logins and history are in there; other users of this PC could read them.',
|
|
122
|
+
plan: 'make ' + dir + ' private (you, SYSTEM and Administrators only)',
|
|
123
|
+
data: dir,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
fix: (_env, finding) => {
|
|
127
|
+
const dir = String(finding.data);
|
|
128
|
+
// A folder with files is walked file by file (a few hundred thousand take minutes), and this waits for it: the
|
|
129
|
+
// only other way is a hand-made icacls command, which is easier to get wrong than this script.
|
|
130
|
+
if (holdsData(dir))
|
|
131
|
+
console.log('Changing the permissions of everything in ' + dir + '. This can take minutes.');
|
|
132
|
+
protectPrivateFolder(dir, { walkAll: true });
|
|
133
|
+
return { done: 'made ' + dir + ' private' };
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'machine-stale-acl',
|
|
138
|
+
group: 'Data folder',
|
|
139
|
+
name: 'Sharing permissions',
|
|
140
|
+
applies: (env) => machine(env) && Boolean(env.record?.groupSid),
|
|
141
|
+
needsIdle: 'look',
|
|
142
|
+
timeoutMs: 40_000,
|
|
143
|
+
run: (env) => {
|
|
144
|
+
const priv = privateFolder(env);
|
|
145
|
+
if (!priv)
|
|
146
|
+
return ok('your data folder is not in the shared tree; nothing is opened to the group');
|
|
147
|
+
const folders = sharedFolders(storageOf(env.dataPath), env.dataPath).filter((d) => fs.existsSync(d));
|
|
148
|
+
const stale = [];
|
|
149
|
+
for (const dir of folders) {
|
|
150
|
+
const entries = icaclsOf(env, dir);
|
|
151
|
+
if (entries && groupEntries(entries, SHARING_GROUP).length)
|
|
152
|
+
stale.push(dir);
|
|
153
|
+
}
|
|
154
|
+
if (!stale.length)
|
|
155
|
+
return ok('the group "' + SHARING_GROUP + '" has no access to your folders (nothing is shared)');
|
|
156
|
+
return {
|
|
157
|
+
status: 'needs-you',
|
|
158
|
+
detail: 'the group "' + SHARING_GROUP + '" still has access to ' + plural(stale.length, 'of your folder'),
|
|
159
|
+
means: 'Others could enter your data folder although you are not sharing a sandbox.',
|
|
160
|
+
plan: 'remove the group from ' + plural(stale.length, 'folder') + ' (only those entries; nothing inside changes)',
|
|
161
|
+
lines: stale,
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
fix: (env) => {
|
|
165
|
+
const sid = env.record?.groupSid;
|
|
166
|
+
if (!sid)
|
|
167
|
+
throw new Error('install.json has no group');
|
|
168
|
+
applyAcl(sharingAclPlan({ storageUserDir: storageOf(env.dataPath), dataPath: env.dataPath, groupSid: sid, on: false }));
|
|
169
|
+
return { done: 'removed the group from your folders' };
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: 'machine-run-shared',
|
|
174
|
+
group: 'Data folder',
|
|
175
|
+
name: 'Shared run folder',
|
|
176
|
+
applies: (env) => machine(env) && Boolean(env.record?.groupSid),
|
|
177
|
+
timeoutMs: 40_000,
|
|
178
|
+
run: (env) => {
|
|
179
|
+
if (!sharedRecord(env))
|
|
180
|
+
return ok('no sandbox of yours is shared right now');
|
|
181
|
+
const run = path.join(env.dataPath, 'run');
|
|
182
|
+
const entries = icaclsOf(env, run);
|
|
183
|
+
if (!entries)
|
|
184
|
+
return { status: 'skipped', detail: 'could not read the permissions of ' + run };
|
|
185
|
+
if (groupEntries(entries, SHARING_GROUP).length)
|
|
186
|
+
return ok('the group can use ' + run);
|
|
187
|
+
return {
|
|
188
|
+
status: 'warn',
|
|
189
|
+
detail: 'your sandbox is shared but the group cannot use ' + run,
|
|
190
|
+
means: 'Others cannot attach to it or run commands in it.',
|
|
191
|
+
plan: 'open ' + run + ' to the group again',
|
|
192
|
+
};
|
|
193
|
+
},
|
|
194
|
+
fix: (env) => {
|
|
195
|
+
const sid = env.record?.groupSid;
|
|
196
|
+
if (!sid)
|
|
197
|
+
throw new Error('install.json has no group');
|
|
198
|
+
applyAcl(sharingAclPlan({ storageUserDir: storageOf(env.dataPath), dataPath: env.dataPath, groupSid: sid, on: true }));
|
|
199
|
+
return { done: 'opened the run folder to the group' };
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: 'machine-active-records',
|
|
204
|
+
group: 'Sandbox',
|
|
205
|
+
name: 'Sharing records',
|
|
206
|
+
applies: machine,
|
|
207
|
+
run: (env) => {
|
|
208
|
+
const all = records(env).readAll();
|
|
209
|
+
const stale = staleActiveRecords(all, env.system.processes());
|
|
210
|
+
if (!stale.length)
|
|
211
|
+
return ok(all.length ? plural(all.length, 'record') + ', all of a running sandbox' : 'none');
|
|
212
|
+
return {
|
|
213
|
+
status: 'needs-you',
|
|
214
|
+
detail: plural(stale.length, 'record') +
|
|
215
|
+
' of sandboxes that are no longer running (' +
|
|
216
|
+
stale.map((r) => r.user).join(', ') +
|
|
217
|
+
')',
|
|
218
|
+
means: 'They can make other users think a sandbox is running or whose it is.',
|
|
219
|
+
plan: 'remove ' + plural(stale.length, 'stale record'),
|
|
220
|
+
data: stale.map((r) => r.sid),
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
fix: (env, finding) => {
|
|
224
|
+
const sids = Array.isArray(finding.data) ? finding.data : [];
|
|
225
|
+
// Looked at again now: a sandbox that started since is not removed.
|
|
226
|
+
const still = staleActiveRecords(records(env).readAll(), env.system.processes()).filter((r) => sids.includes(r.sid));
|
|
227
|
+
for (const r of still)
|
|
228
|
+
records(env).clear(r.sid);
|
|
229
|
+
return { done: 'removed ' + plural(still.length, 'stale record') };
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Check } from '../types.js';
|
|
2
|
+
/** The first proxy variable that is set: [name, value]. */
|
|
3
|
+
export declare function proxyFromEnvironment(env?: NodeJS.ProcessEnv): [string, string] | null;
|
|
4
|
+
/** null when the value is a proxy address the downloads can use, else why not. */
|
|
5
|
+
export declare function proxyProblem(value: string): string | null;
|
|
6
|
+
export declare const NETWORK_CHECKS: Check[];
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ok } from './common.js';
|
|
2
|
+
const PROXY_VARIABLES = ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'ALL_PROXY', 'all_proxy'];
|
|
3
|
+
const REACH_MS = 6000;
|
|
4
|
+
/** The first proxy variable that is set: [name, value]. */
|
|
5
|
+
export function proxyFromEnvironment(env = process.env) {
|
|
6
|
+
for (const name of PROXY_VARIABLES) {
|
|
7
|
+
const value = env[name]?.trim();
|
|
8
|
+
if (value)
|
|
9
|
+
return [name, value];
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
/** null when the value is a proxy address the downloads can use, else why not. */
|
|
14
|
+
export function proxyProblem(value) {
|
|
15
|
+
try {
|
|
16
|
+
const url = new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(value) ? value : 'http://' + value);
|
|
17
|
+
return url.hostname ? null : 'it has no host name';
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return 'it is not an address';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export const NETWORK_CHECKS = [
|
|
24
|
+
{
|
|
25
|
+
id: 'net-proxy',
|
|
26
|
+
group: 'Network',
|
|
27
|
+
name: 'Proxy',
|
|
28
|
+
run: () => {
|
|
29
|
+
const proxy = proxyFromEnvironment();
|
|
30
|
+
if (!proxy)
|
|
31
|
+
return ok('no proxy variable set');
|
|
32
|
+
const problem = proxyProblem(proxy[1]);
|
|
33
|
+
if (!problem)
|
|
34
|
+
return ok(proxy[0] + ' = ' + proxy[1].replace(/\/\/[^@/]*@/, '//***@'));
|
|
35
|
+
return {
|
|
36
|
+
status: 'warn',
|
|
37
|
+
detail: proxy[0] + ' is set but ' + problem,
|
|
38
|
+
means: 'Downloads that follow the proxy settings will fail.',
|
|
39
|
+
fix: 'Set ' + proxy[0] + ' to an address like http://proxy.example.com:8080, or remove it.',
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'net-github',
|
|
45
|
+
group: 'Network',
|
|
46
|
+
name: 'GitHub',
|
|
47
|
+
checking: 'whether GitHub can be reached',
|
|
48
|
+
timeoutMs: REACH_MS + 4000,
|
|
49
|
+
run: async (env) => {
|
|
50
|
+
if (await env.system.reachable('https://github.com', REACH_MS))
|
|
51
|
+
return ok('github.com answers');
|
|
52
|
+
return {
|
|
53
|
+
status: 'warn',
|
|
54
|
+
detail: 'github.com did not answer within ' + REACH_MS / 1000 + ' seconds',
|
|
55
|
+
means: 'Updates and some tool downloads need it. Without it they fail or use what is already saved.',
|
|
56
|
+
fix: 'Check your internet connection, VPN or proxy, then run this again.',
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
];
|