Files
PowerToys/src/modules/Workspaces/WorkspacesCsharpLibrary/Utils/FolderUtils.cs

42 lines
1.5 KiB
C#
Raw Normal View History

Cmdpal extension: Powertoys extension for cmdpal (#44006) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Installer built, and every command works as expected, Now use sparse app deployment, so we don't need an extra msix --------- Co-authored-by: kaitao-ms <kaitao1105@gmail.com>
2025-12-23 21:07:44 +08:00
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
namespace WorkspacesCsharpLibrary.Utils;
public class FolderUtils
{
public static string Desktop()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
}
public static string Temp()
{
return Path.GetTempPath();
}
Workspaces v6: route the WPF Editor read/write through the settings service This is the core integration that makes the EoP protection actually take effect: the Editor now persists settings through PTSettingsSvc instead of writing workspaces.json directly into the protected folder (which would be denied for a non-elevated user). WorkspacesEditorIO: - ParseWorkspaces (read): GetBlob -> WorkspacesData.Deserialize, using the SAME serializer/format as before (native Launcher stays compatible). NotFound -> empty; Unavailable -> legacy %LocalAppData% file fallback (no-admin only, §10). - SerializeWorkspaces (write): WorkspacesData.Serialize -> PutBlob; Unavailable -> legacy file fallback. The transient snapshot->editor temp file stays direct IO. - Fires SettingsBootstrapper.EnsureInitialized at editor open (the per-user deferred-init / migration trigger the design called for). FolderUtils.DataFolder() reverted to the user-writable %LocalAppData% working folder. v6 had repointed it at the protected %ProgramData% store, which also broke the Editor's icons and temp-project handoff (those need to stay user-writable). The protected store is reached only through the service now. Verified locally (harness compiling the real source files, run as an allow-listed PowerToys.WorkspacesEditor.exe against the dev service) — 8/8: Serialize->PutBlob Ok, GetBlob->Deserialize round-trips, dash-case JSON lands in the protected %ProgramData%\\...\\blob.bin (owner NT SERVICE\\PTSettingsSvc, user RX), non-elevated write+delete rejected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-29 00:05:06 +08:00
// User-writable working folder for the Editor's transient files (icons,
// temp-project handoff) AND the legacy / no-service fallback store.
//
// v6 note: the *protected* settings store does NOT live here — it is the
// service-managed blob under %ProgramData% (see SettingsPaths / §9). The
// Editor reads/writes the real settings through PTSettingsClient
// (GetBlob / PutBlob); this %LocalAppData% path is only the working dir and
// the no-service fallback, both of which must stay user-writable.
Cmdpal extension: Powertoys extension for cmdpal (#44006) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Installer built, and every command works as expected, Now use sparse app deployment, so we don't need an extra msix --------- Co-authored-by: kaitao-ms <kaitao1105@gmail.com>
2025-12-23 21:07:44 +08:00
public static string DataFolder()
Workspaces EoP v6 prototype: settings file behind local Windows service Drops every v5 launcher-gating element (Authenticode / MS publisher / ProgramFiles path / empty-args triple-AND) and tackles the EoP from the other end: same-user malware can no longer modify workspaces.json because the file lives under a DACL that only the new PTWorkspacesSvc service can write. Components: - WorkspacesSettingsService/ native C++ service exe (SCM + --console) using NT SERVICE\PTWorkspacesSvc virtual account; protocol/Protocol.h holds the tiny wire format (5 opcodes). - WorkspacesSettingsClient/ native static lib used by Editor / SnapshotTool / smoke test. - WorkspacesCsharpLibrary/ SettingsService/ managed mirror: client, paths, one-shot legacy migration helper. - WorkspacesSettingsService.wxs ServiceInstall (virtual account, demand start, restart-on-failure) + ServiceControl + CreateFolder with protected DACL on the data root. Caller authentication (no signatures, by design): 1. ImpersonateNamedPipeClient -> token must be a real interactive user (rejects SYSTEM / SERVICE / Anonymous). 2. GetNamedPipeClientProcessId -> caller image path must be under the MSI-recorded PT install folder. 3. Image filename must match a tiny allow-list (Editor / SnapshotTool / runner). The launcher is *not* on the list; it only reads, and reads via the user's R+X grant on the file's DACL. End-to-end verified on dev box: - Smoke test from arbitrary folder -> AuthRejected (allow-list works). - Smoke test renamed + located under a PT_DEV_INSTALL_FOLDER override -> Ping=Ok, GetSettings=Ok (empty for first-time user). - PutSettings completes against the service exe but errors on the DACL apply because the NT SERVICE\PTWorkspacesSvc account only exists after CreateService runs -- confirms the DACL is in fact being applied against the right principal. See Workspaces-EoP-Fix/Design-v6-Prototype-Notes.md for the threat model, wire protocol, reproduction steps, and the list of known gaps before this can graduate from prototype.
2026-06-10 15:03:20 +08:00
{
Workspaces v6: route the WPF Editor read/write through the settings service This is the core integration that makes the EoP protection actually take effect: the Editor now persists settings through PTSettingsSvc instead of writing workspaces.json directly into the protected folder (which would be denied for a non-elevated user). WorkspacesEditorIO: - ParseWorkspaces (read): GetBlob -> WorkspacesData.Deserialize, using the SAME serializer/format as before (native Launcher stays compatible). NotFound -> empty; Unavailable -> legacy %LocalAppData% file fallback (no-admin only, §10). - SerializeWorkspaces (write): WorkspacesData.Serialize -> PutBlob; Unavailable -> legacy file fallback. The transient snapshot->editor temp file stays direct IO. - Fires SettingsBootstrapper.EnsureInitialized at editor open (the per-user deferred-init / migration trigger the design called for). FolderUtils.DataFolder() reverted to the user-writable %LocalAppData% working folder. v6 had repointed it at the protected %ProgramData% store, which also broke the Editor's icons and temp-project handoff (those need to stay user-writable). The protected store is reached only through the service now. Verified locally (harness compiling the real source files, run as an allow-listed PowerToys.WorkspacesEditor.exe against the dev service) — 8/8: Serialize->PutBlob Ok, GetBlob->Deserialize round-trips, dash-case JSON lands in the protected %ProgramData%\\...\\blob.bin (owner NT SERVICE\\PTSettingsSvc, user RX), non-elevated write+delete rejected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-29 00:05:06 +08:00
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Microsoft\\PowerToys\\Workspaces";
Workspaces EoP v6 prototype: settings file behind local Windows service Drops every v5 launcher-gating element (Authenticode / MS publisher / ProgramFiles path / empty-args triple-AND) and tackles the EoP from the other end: same-user malware can no longer modify workspaces.json because the file lives under a DACL that only the new PTWorkspacesSvc service can write. Components: - WorkspacesSettingsService/ native C++ service exe (SCM + --console) using NT SERVICE\PTWorkspacesSvc virtual account; protocol/Protocol.h holds the tiny wire format (5 opcodes). - WorkspacesSettingsClient/ native static lib used by Editor / SnapshotTool / smoke test. - WorkspacesCsharpLibrary/ SettingsService/ managed mirror: client, paths, one-shot legacy migration helper. - WorkspacesSettingsService.wxs ServiceInstall (virtual account, demand start, restart-on-failure) + ServiceControl + CreateFolder with protected DACL on the data root. Caller authentication (no signatures, by design): 1. ImpersonateNamedPipeClient -> token must be a real interactive user (rejects SYSTEM / SERVICE / Anonymous). 2. GetNamedPipeClientProcessId -> caller image path must be under the MSI-recorded PT install folder. 3. Image filename must match a tiny allow-list (Editor / SnapshotTool / runner). The launcher is *not* on the list; it only reads, and reads via the user's R+X grant on the file's DACL. End-to-end verified on dev box: - Smoke test from arbitrary folder -> AuthRejected (allow-list works). - Smoke test renamed + located under a PT_DEV_INSTALL_FOLDER override -> Ping=Ok, GetSettings=Ok (empty for first-time user). - PutSettings completes against the service exe but errors on the DACL apply because the NT SERVICE\PTWorkspacesSvc account only exists after CreateService runs -- confirms the DACL is in fact being applied against the right principal. See Workspaces-EoP-Fix/Design-v6-Prototype-Notes.md for the threat model, wire protocol, reproduction steps, and the list of known gaps before this can graduate from prototype.
2026-06-10 15:03:20 +08:00
}
Workspaces v6: route the WPF Editor read/write through the settings service This is the core integration that makes the EoP protection actually take effect: the Editor now persists settings through PTSettingsSvc instead of writing workspaces.json directly into the protected folder (which would be denied for a non-elevated user). WorkspacesEditorIO: - ParseWorkspaces (read): GetBlob -> WorkspacesData.Deserialize, using the SAME serializer/format as before (native Launcher stays compatible). NotFound -> empty; Unavailable -> legacy %LocalAppData% file fallback (no-admin only, §10). - SerializeWorkspaces (write): WorkspacesData.Serialize -> PutBlob; Unavailable -> legacy file fallback. The transient snapshot->editor temp file stays direct IO. - Fires SettingsBootstrapper.EnsureInitialized at editor open (the per-user deferred-init / migration trigger the design called for). FolderUtils.DataFolder() reverted to the user-writable %LocalAppData% working folder. v6 had repointed it at the protected %ProgramData% store, which also broke the Editor's icons and temp-project handoff (those need to stay user-writable). The protected store is reached only through the service now. Verified locally (harness compiling the real source files, run as an allow-listed PowerToys.WorkspacesEditor.exe against the dev service) — 8/8: Serialize->PutBlob Ok, GetBlob->Deserialize round-trips, dash-case JSON lands in the protected %ProgramData%\\...\\blob.bin (owner NT SERVICE\\PTSettingsSvc, user RX), non-elevated write+delete rejected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-29 00:05:06 +08:00
// The pre-v6 location. Same as DataFolder() now; kept as a distinct name
// for the one-shot migration source and the no-service fallback.
Workspaces EoP v6 prototype: settings file behind local Windows service Drops every v5 launcher-gating element (Authenticode / MS publisher / ProgramFiles path / empty-args triple-AND) and tackles the EoP from the other end: same-user malware can no longer modify workspaces.json because the file lives under a DACL that only the new PTWorkspacesSvc service can write. Components: - WorkspacesSettingsService/ native C++ service exe (SCM + --console) using NT SERVICE\PTWorkspacesSvc virtual account; protocol/Protocol.h holds the tiny wire format (5 opcodes). - WorkspacesSettingsClient/ native static lib used by Editor / SnapshotTool / smoke test. - WorkspacesCsharpLibrary/ SettingsService/ managed mirror: client, paths, one-shot legacy migration helper. - WorkspacesSettingsService.wxs ServiceInstall (virtual account, demand start, restart-on-failure) + ServiceControl + CreateFolder with protected DACL on the data root. Caller authentication (no signatures, by design): 1. ImpersonateNamedPipeClient -> token must be a real interactive user (rejects SYSTEM / SERVICE / Anonymous). 2. GetNamedPipeClientProcessId -> caller image path must be under the MSI-recorded PT install folder. 3. Image filename must match a tiny allow-list (Editor / SnapshotTool / runner). The launcher is *not* on the list; it only reads, and reads via the user's R+X grant on the file's DACL. End-to-end verified on dev box: - Smoke test from arbitrary folder -> AuthRejected (allow-list works). - Smoke test renamed + located under a PT_DEV_INSTALL_FOLDER override -> Ping=Ok, GetSettings=Ok (empty for first-time user). - PutSettings completes against the service exe but errors on the DACL apply because the NT SERVICE\PTWorkspacesSvc account only exists after CreateService runs -- confirms the DACL is in fact being applied against the right principal. See Workspaces-EoP-Fix/Design-v6-Prototype-Notes.md for the threat model, wire protocol, reproduction steps, and the list of known gaps before this can graduate from prototype.
2026-06-10 15:03:20 +08:00
public static string LegacyDataFolder()
Cmdpal extension: Powertoys extension for cmdpal (#44006) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Installer built, and every command works as expected, Now use sparse app deployment, so we don't need an extra msix --------- Co-authored-by: kaitao-ms <kaitao1105@gmail.com>
2025-12-23 21:07:44 +08:00
{
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Microsoft\\PowerToys\\Workspaces";
}
}