Skip to content

Commit

Permalink
Elevate/de-elevate for protocol-invoked fix application
Browse files Browse the repository at this point in the history
  • Loading branch information
KimihikoAkayasaki committed Nov 15, 2024
1 parent 0dd8745 commit 2d27aec
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 208 deletions.
73 changes: 59 additions & 14 deletions Amethyst/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -512,14 +512,25 @@ protected override async void OnLaunched(LaunchActivatedEventArgs eventArgs)
{
try
{
// Read the query string
var queryDictionary = HttpUtility
.ParseQueryString(activationUri!.Query.TrimStart('?'));

// Read all needed query parameters
var pluginGuid = queryDictionary["Guid"];
var fixName = queryDictionary["FixName"];
var param = queryDictionary["Param"];
string pluginGuid, fixName, param;
if (!string.IsNullOrEmpty(activationUri!.Fragment.TrimStart('#')))
{
// "amethyst-app:apply-fix#GuidK2VRTEAM-AME2-APII-DVCE-DVCEKINECTV1FixNameNotPoweredFixParam0End"
pluginGuid = activationUri.Fragment.Substring("Guid", "FixName");
fixName = activationUri.Fragment.Substring("FixName", "Param");
param = activationUri.Fragment.Substring("Param", "End");
}
else
{
// Read the query string
var queryDictionary = HttpUtility
.ParseQueryString(activationUri!.Query.TrimStart('?'));

// Read all needed query parameters
pluginGuid = queryDictionary["Guid"];
fixName = queryDictionary["FixName"];
param = queryDictionary["Param"];
}

Logger.Info($"Received fix application request: " +
$"Plugin{{{pluginGuid}}}, Fix Name{{{fixName}}}, Param{{{param}}}");
Expand Down Expand Up @@ -594,18 +605,22 @@ protected override async void OnLaunched(LaunchActivatedEventArgs eventArgs)
var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromMinutes(1));

if (!FileUtils.IsCurrentProcessElevated() && pluginGuid is "K2VRTEAM-AME2-APII-DVCE-DVCEKINECTV1")
{
// "amethyst-app:apply-fix#GuidK2VRTEAM-AME2-APII-DVCE-DVCEKINECTV1FixNameNotPoweredFixParam0End"
Logger.Warn("Amethyst is not elevated, but the fix will likely require administrative privileges! Restarting...");
await Interfacing.ExecuteAppRestart(admin: true, filenameOverride: "powershell.exe",
parameters: $"-command \"Start-Process -FilePath 'amethyst-app:apply-fix#Guid{pluginGuid}FixName{fixName}Param{param}End'\"");
}

// Loop over all dependencies and install them, give up on failures
try
{
// Prepare the progress update handler
var progress = new Progress<InstallationProgress>();
progress.ProgressChanged += (_, installationProgress) =>
Shared.Main.DispatcherQueue.TryEnqueue(() =>
{
// Update our progress here
Logger.Info($"Applying fix \"{fixName}\" from {{{pluginGuid}}}: " +
$"{installationProgress.StageTitle} - {installationProgress.OverallProgress}");
});
Logger.Info($"Applying fix \"{fixName}\" from {{{pluginGuid}}}: " +
$"{installationProgress.StageTitle} - {installationProgress.OverallProgress}");

// Capture the installation thread
var installationWorker = fix.Apply(progress, tokenSource.Token, param);
Expand Down Expand Up @@ -1279,4 +1294,34 @@ public static async Task<Dictionary<TKey, TValue>> ToDictionaryAsync<TInput, TKe

return dictionary;
}
}

public static class StringExtensions
{
/// <summary>
/// takes a substring between two anchor strings (or the end of the string if that anchor is null)
/// </summary>
/// <param name="this">a string</param>
/// <param name="from">an optional string to search after</param>
/// <param name="until">an optional string to search before</param>
/// <param name="comparison">an optional comparison for the search</param>
/// <returns>a substring based on the search</returns>
public static string Substring(this string @this, string from = null, string until = null, StringComparison comparison = StringComparison.InvariantCulture)
{
var fromLength = (from ?? string.Empty).Length;
var startIndex = !string.IsNullOrEmpty(from)
? @this.IndexOf(from, comparison) + fromLength
: 0;

if (startIndex < fromLength) throw new ArgumentException("from: Failed to find an instance of the first anchor");

var endIndex = !string.IsNullOrEmpty(until)
? @this.IndexOf(until, startIndex, comparison)
: @this.Length;

if (endIndex < 0) throw new ArgumentException("until: Failed to find an instance of the last anchor");

var subString = @this.Substring(startIndex, endIndex - startIndex);
return subString;
}
}
99 changes: 62 additions & 37 deletions Amethyst/Classes/Interfacing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Microsoft.Windows.AppNotifications;
using Newtonsoft.Json;
using System.Threading;
using static Amethyst.Classes.Shared;

namespace Amethyst.Classes;

Expand Down Expand Up @@ -203,23 +204,44 @@ public static void ShowServiceToast(string header, string text)
public static void ShowToast(string header, string text,
bool highPriority = false, string action = "none")
{
var payload =
$"<toast launch=\"action={action}&amp;actionId=00000\">" +
"<visual><binding template = \"ToastGeneric\">" +
(string.IsNullOrEmpty(header) ? "" : $"<text>{header}</text>") +
(string.IsNullOrEmpty(text) ? "" : $"<text>{text}</text>") +
"</binding></visual></toast>";

AppNotification toast = new(payload)
if (!FileUtils.IsCurrentProcessElevated())
{
Tag = "Tag_AmethystNotifications",
Group = "Group_AmethystNotifications",
Priority = highPriority
? AppNotificationPriority.High
: AppNotificationPriority.Default
};

Shared.Main.NotificationManager?.Show(toast);
var payload =
$"<toast launch=\"action={action}&amp;actionId=00000\">" +
"<visual><binding template = \"ToastGeneric\">" +
(string.IsNullOrEmpty(header) ? "" : $"<text>{header}</text>") +
(string.IsNullOrEmpty(text) ? "" : $"<text>{text}</text>") +
"</binding></visual></toast>";

AppNotification toast = new(payload)
{
Tag = "Tag_AmethystNotifications",
Group = "Group_AmethystNotifications",
Priority = highPriority
? AppNotificationPriority.High
: AppNotificationPriority.Default
};

Shared.Main.NotificationManager?.Show(toast);
}
else if (File.Exists(ProgramLocation.FullName))
{
// Log the caller
Logger.Info($"The current caller process is: {ProgramLocation.FullName}");

try
{
Process.Start(new ProcessStartInfo
{
Arguments = $"amethyst-app:crash-notification#{header}+{text}",
FileName = "explorer.exe"
});
}
catch (Exception e)
{
Logger.Error(e);
}
}
}

[DllImport("user32.dll")]
Expand Down Expand Up @@ -249,14 +271,14 @@ public static void ProcessToastArguments(
await Task.Delay(500);
}

Shared.Settings.PageMainScrollViewer.UpdateLayout();
Shared.Settings.PageMainScrollViewer.ChangeView(null,
Shared.Settings.PageMainScrollViewer.ExtentHeight / 2.0, null);
Settings.PageMainScrollViewer.UpdateLayout();
Settings.PageMainScrollViewer.ChangeView(null,
Settings.PageMainScrollViewer.ExtentHeight / 2.0, null);

await Task.Delay(500);

// Focus on the restart button
Shared.Settings.CheckOverlapsCheckBox.Focus(FocusState.Keyboard);
Settings.CheckOverlapsCheckBox.Focus(FocusState.Keyboard);
});

// When you need to restart OpenVR
Expand All @@ -279,14 +301,14 @@ public static void ProcessToastArguments(
await Task.Delay(500);
}

Shared.Settings.PageMainScrollViewer.UpdateLayout();
Shared.Settings.PageMainScrollViewer.ChangeView(null,
Shared.Settings.PageMainScrollViewer.ExtentHeight, null);
Settings.PageMainScrollViewer.UpdateLayout();
Settings.PageMainScrollViewer.ChangeView(null,
Settings.PageMainScrollViewer.ExtentHeight, null);

await Task.Delay(500);

// Focus on the restart button
Shared.Settings.RestartButton.Focus(FocusState.Keyboard);
Settings.RestartButton.Focus(FocusState.Keyboard);
});

// Else no click action requested ("none")
Expand Down Expand Up @@ -471,8 +493,8 @@ public static async void ServiceEndpointSetup()
// Sleep a bit before checking
await Task.Delay(1000);

if (Shared.General.ErrorWhatText is not null &&
Shared.General.ErrorWhatText.Visibility == Visibility.Visible)
if (General.ErrorWhatText is not null &&
General.ErrorWhatText.Visibility == Visibility.Visible)
AppSounds.PlayAppSound(AppSounds.AppSoundType.Error);
});

Expand All @@ -494,19 +516,19 @@ public static (Vector3 Position, Quaternion Orientation)
public static void UpdateServerStatus()
{
// Block some things if server isn't working properly
if (Shared.General.ErrorWhatText is null || IsServiceEndpointPresent) return;
if (General.ErrorWhatText is null || IsServiceEndpointPresent) return;
Logger.Info("[Server Error] Entering the server error state...");

// Hide device error labels (if any)
Shared.General.ErrorWhatText.Visibility = Visibility.Collapsed;
Shared.General.ErrorWhatGrid.Visibility = Visibility.Collapsed;
Shared.General.ErrorButtonsGrid.Visibility = Visibility.Collapsed;
Shared.General.TrackingDeviceErrorLabel.Visibility = Visibility.Collapsed;
General.ErrorWhatText.Visibility = Visibility.Collapsed;
General.ErrorWhatGrid.Visibility = Visibility.Collapsed;
General.ErrorButtonsGrid.Visibility = Visibility.Collapsed;
General.TrackingDeviceErrorLabel.Visibility = Visibility.Collapsed;

// Block spawn|offsets|calibration buttons
Shared.General.ToggleTrackersButton.IsEnabled = false;
Shared.General.CalibrationButton.IsEnabled = false;
Shared.General.OffsetsButton.IsEnabled = false;
General.ToggleTrackersButton.IsEnabled = false;
General.CalibrationButton.IsEnabled = false;
General.OffsetsButton.IsEnabled = false;
}

[DllImport("user32.dll")]
Expand Down Expand Up @@ -832,7 +854,8 @@ public static string EnglishJsonString(string resourceKey,
}

// Restart Amethyst
public static async Task ExecuteAppRestart(bool handleExit = true, string parameters = "", bool admin = false)
public static async Task ExecuteAppRestart(bool handleExit = true,
string parameters = "", bool admin = false, string filenameOverride = null)
{
Logger.Info("Restart requested: trying to restart the app...");

Expand All @@ -853,7 +876,7 @@ public static async Task ExecuteAppRestart(bool handleExit = true, string parame

var info = new ProcessStartInfo
{
FileName = ProgramLocation.FullName.Replace(".dll", ".exe"),
FileName = filenameOverride ?? ProgramLocation.FullName.Replace(".dll", ".exe"),
Arguments = parameters // Pass same args
};

Expand Down Expand Up @@ -1196,7 +1219,7 @@ public static void RefreshApplicationInterface()
Shared.Main.DispatcherQueue.TryEnqueue(() =>
{
// Force refresh all the valid pages
Shared.Events.RequestInterfaceReload(false);
Events.RequestInterfaceReload(false);

// Optionally hide other status errors
UpdateServerStatus();
Expand All @@ -1206,6 +1229,8 @@ public static void RefreshApplicationInterface()

public static void SetupNotificationManager()
{
if (FileUtils.IsCurrentProcessElevated()) return;

try
{
Logger.Info("Registering for NotificationInvoked WinRT event...");
Expand Down
Loading

0 comments on commit 2d27aec

Please sign in to comment.