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();
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
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
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
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()
|
2025-12-23 21:07:44 +08:00
|
|
|
{
|
|
|
|
|
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Microsoft\\PowerToys\\Workspaces";
|
|
|
|
|
}
|
|
|
|
|
}
|