-
Notifications
You must be signed in to change notification settings - Fork 0
Add uninstall actions for Explorer integration #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
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 340705a
Merge branch 'main' into codex/uninstall-quickstart
MEMZ-Edge01 b1f924a
Fix Explorer integration uninstall safeguards
MEMZ-Edge01 d3b808f
Prevent stale Explorer integration operations from releasing the gate
MEMZ-Edge01 1b60640
Reduce complexity in Explorer integration flow
MEMZ-Edge01 4e98584
Clarify history progress calculation
MEMZ-Edge01 6de4535
Fix Explorer integration maintenance races
MEMZ-Edge01 145c319
Fix Explorer integration identity fallback
MEMZ-Edge01 6caf050
Merge branch 'main' into codex/uninstall-quickstart
MEMZ-Edge01 41e5abd
Harden Explorer integration maintenance
MEMZ-Edge01 629df3e
Align Explorer integration status identity
MEMZ-Edge01 d843950
Scope Explorer maintenance to current install
MEMZ-Edge01 97ec6ad
Preserve sibling Explorer integrations
MEMZ-Edge01 9f495e2
Guard certificate removal by certificate publisher
MEMZ-Edge01 3fd8bba
Surface certificate store access failures
MEMZ-Edge01 65fce5b
Preserve sibling Explorer integration settings
MEMZ-Edge01 20f1532
Gate Explorer updates during maintenance
MEMZ-Edge01 e0a3eb3
Defer language updates and tolerate malformed paths
MEMZ-Edge01 fd45b46
Avoid re-enumerating failing certificate stores
MEMZ-Edge01 859cc5a
Guard machine certificate removal against other users
MEMZ-Edge01 06704b1
Run all-user certificate guard in the elevated helper
MEMZ-Edge01 c4c036a
Tolerate malformed package data and report sibling-aware uninstall
MEMZ-Edge01 dde653f
Merge concurrent settings changes during language save
MEMZ-Edge01 8a2f064
Catch package enumeration failures during certificate removal
MEMZ-Edge01 e57aaec
Preserve publisher quotes in elevated certificate guard
MEMZ-Edge01 632a55f
Tolerate package enumeration failures in status checks
MEMZ-Edge01 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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
115
src/ClipPort/Services/ExplorerContextMenuConfigurationPolicy.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)); | ||
|
|
||
| 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)) | ||
| }; | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.