Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9848019
Add Explorer integration uninstall actions
MEMZ-Edge01 Aug 9, 2026
340705a
Merge branch 'main' into codex/uninstall-quickstart
MEMZ-Edge01 Aug 9, 2026
b1f924a
Fix Explorer integration uninstall safeguards
MEMZ-Edge01 Aug 9, 2026
d3b808f
Prevent stale Explorer integration operations from releasing the gate
MEMZ-Edge01 Aug 9, 2026
1b60640
Reduce complexity in Explorer integration flow
MEMZ-Edge01 Aug 9, 2026
4e98584
Clarify history progress calculation
MEMZ-Edge01 Aug 9, 2026
6de4535
Fix Explorer integration maintenance races
MEMZ-Edge01 Aug 9, 2026
145c319
Fix Explorer integration identity fallback
MEMZ-Edge01 Aug 9, 2026
6caf050
Merge branch 'main' into codex/uninstall-quickstart
MEMZ-Edge01 Aug 9, 2026
41e5abd
Harden Explorer integration maintenance
MEMZ-Edge01 Aug 9, 2026
629df3e
Align Explorer integration status identity
MEMZ-Edge01 Aug 9, 2026
d843950
Scope Explorer maintenance to current install
MEMZ-Edge01 Aug 9, 2026
97ec6ad
Preserve sibling Explorer integrations
MEMZ-Edge01 Aug 9, 2026
9f495e2
Guard certificate removal by certificate publisher
MEMZ-Edge01 Aug 10, 2026
3fd8bba
Surface certificate store access failures
MEMZ-Edge01 Aug 10, 2026
65fce5b
Preserve sibling Explorer integration settings
MEMZ-Edge01 Aug 10, 2026
20f1532
Gate Explorer updates during maintenance
MEMZ-Edge01 Aug 10, 2026
e0a3eb3
Defer language updates and tolerate malformed paths
MEMZ-Edge01 Aug 10, 2026
fd45b46
Avoid re-enumerating failing certificate stores
MEMZ-Edge01 Aug 10, 2026
859cc5a
Guard machine certificate removal against other users
MEMZ-Edge01 Aug 10, 2026
06704b1
Run all-user certificate guard in the elevated helper
MEMZ-Edge01 Aug 10, 2026
c4c036a
Tolerate malformed package data and report sibling-aware uninstall
MEMZ-Edge01 Aug 10, 2026
dde653f
Merge concurrent settings changes during language save
MEMZ-Edge01 Aug 10, 2026
8a2f064
Catch package enumeration failures during certificate removal
MEMZ-Edge01 Aug 10, 2026
e57aaec
Preserve publisher quotes in elevated certificate guard
MEMZ-Edge01 Aug 10, 2026
632a55f
Tolerate package enumeration failures in status checks
MEMZ-Edge01 Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 246 additions & 30 deletions src/ClipPort/MainWindow.Settings.cs

Large diffs are not rendered by default.

342 changes: 245 additions & 97 deletions src/ClipPort/MainWindow.xaml.cs

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/ClipPort/Services/CertificateInstallerWorkflow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Diagnostics;

namespace ClipPort.Services;

internal static class CertificateInstallerWorkflow
{
public static Task WaitForExitAsync(Process process) =>
WaitForExitAsync(process, static currentProcess => currentProcess.WaitForExitAsync());

internal static async Task WaitForExitAsync(
Process process,
Func<Process, Task> waitForExitAsync)
{
using (process)
{
await waitForExitAsync(process);
}
}
}
22 changes: 22 additions & 0 deletions src/ClipPort/Services/CertificateStoreSearch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace ClipPort.Services;

internal static class CertificateStoreSearch
{
public static List<TTarget> FindMatches<TTarget>(
IEnumerable<TTarget> targets,
Func<TTarget, bool> containsCertificate)
{
var matches = new List<TTarget>();
foreach (TTarget target in targets)
{
// Access failures must remain visible to callers so removal cannot
// report success when a certificate store could not be inspected.
if (containsCertificate(target))
{
matches.Add(target);
}
}

return matches;
}
}
115 changes: 115 additions & 0 deletions src/ClipPort/Services/ExplorerContextMenuConfigurationPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
namespace ClipPort.Services;

public sealed record ExplorerContextMenuConfiguration(
bool Enabled,
string Language,
string InstallDirectory);

public static class ExplorerContextMenuConfigurationPolicy
{
public static bool HasSiblingRegistration(
IEnumerable<ExplorerPackageRegistration> registrations,
string expectedPackageName,
string currentExternalPath) =>
registrations.Any(registration =>
string.Equals(
registration.Name,
expectedPackageName,
StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(registration.EffectiveExternalPath) &&
!ExplorerPackageIdentity.ExternalPathsEqual(
registration.EffectiveExternalPath,
currentExternalPath));

public static bool ShouldDeferSynchronizationToConfigurationOwner(
ExplorerContextMenuConfiguration? configuration,
IEnumerable<ExplorerPackageRegistration> registrations,
string expectedPackageName,
string currentExternalPath)
{
List<ExplorerPackageRegistration> packageRegistrations = registrations
.Where(registration =>
string.Equals(
registration.Name,
expectedPackageName,
StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(registration.EffectiveExternalPath))
.ToList();
bool currentPackageRegistered = packageRegistrations.Any(registration =>
ExplorerPackageIdentity.ExternalPathsEqual(
registration.EffectiveExternalPath,
currentExternalPath));

if (!currentPackageRegistered && packageRegistrations.Count > 0)
{
return true;
}

return configuration is not null &&
!ExplorerPackageIdentity.ExternalPathsEqual(
configuration.InstallDirectory,
currentExternalPath) &&
packageRegistrations.Any(registration =>
ExplorerPackageIdentity.ExternalPathsEqual(
registration.EffectiveExternalPath,
configuration.InstallDirectory));
}

public static bool ShouldDisableBeforeRemoval(
ExplorerContextMenuConfiguration? configuration,
IEnumerable<ExplorerPackageRegistration> registrations,
string expectedPackageName,
string removedExternalPath) =>
configuration is not null &&
!registrations.Any(registration =>
string.Equals(
registration.Name,
expectedPackageName,
StringComparison.OrdinalIgnoreCase) &&
!ExplorerPackageIdentity.ExternalPathsEqual(
registration.EffectiveExternalPath,
removedExternalPath) &&
ExplorerPackageIdentity.ExternalPathsEqual(
registration.EffectiveExternalPath,
configuration.InstallDirectory));
Comment thread
MEMZ-Edge01 marked this conversation as resolved.

public static ExplorerContextMenuConfiguration? ReconcileAfterRemoval(
ExplorerContextMenuConfiguration? configuration,
IEnumerable<ExplorerPackageRegistration> remainingRegistrations,
string expectedPackageName)
{
if (configuration is null)
{
return null;
}

List<ExplorerPackageRegistration> candidates = remainingRegistrations
.Where(registration =>
string.Equals(
registration.Name,
expectedPackageName,
StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(registration.EffectiveExternalPath))
.OrderBy(
registration => registration.EffectiveExternalPath,
StringComparer.OrdinalIgnoreCase)
.ThenBy(
registration => registration.Publisher,
StringComparer.OrdinalIgnoreCase)
.ToList();

ExplorerPackageRegistration? replacement = candidates.FirstOrDefault(
registration => ExplorerPackageIdentity.ExternalPathsEqual(
registration.EffectiveExternalPath,
configuration.InstallDirectory)) ??
candidates.FirstOrDefault();

return replacement is null
? null
: configuration with
{
InstallDirectory = Path.TrimEndingDirectorySeparator(
Path.GetFullPath(replacement.EffectiveExternalPath))
};
}
}
Loading