diff --git a/.deepsource.toml b/.deepsource.toml index 2a4202f4c7..227ede7321 100644 --- a/.deepsource.toml +++ b/.deepsource.toml @@ -62,4 +62,4 @@ enabled = false # Disables standardjs transformer [[transformers]] name = "prettier" -enabled = false # Disables prettier transformer +enabled = false # Disables prettier transformer \ No newline at end of file diff --git a/cli-arguments.md b/cli-arguments.md index 95a9988560..0721efa7e7 100644 --- a/cli-arguments.md +++ b/cli-arguments.md @@ -12,10 +12,11 @@ | `--help` | Opens this page | 3.2.0+ | | `--import-settings file` | Imports UniGetUI settings from json file _file_. The file must exist. The old settings will be lost* | 3.2.0+ | | `--export-settings file` | Exports UniGetUI settings to json file _file_. The file will be created or overwritten* | 3.2.0+ | -| `--enable-setting key` | Enables the boolean setting _key_* | 3.2.0+ | -| `--disable-setting key` | Disables the boolean setting _key_* | 3.2.0+ | +| `--[enable\|disable]-setting key` | Enables/disables the boolean setting _key_* | 3.2.0+ | | `--set-setting-value key value` | Sets the value _value_ to the non-boolean setting _key_. To clear a non-boolean setting, `--disable-setting` can be used* | 3.2.0+ | | `--no-corrupt-dialog` | Will show a verbose error message (the error report) instead of a simplified message dialog | 3.2.1+ | +| `--[enable\|disable]-secure-setting-for-user username key` | Enables/disables the given secure setting for the given username. Requires administrator rights. | 3.2.1+ | +| `--[enable\|disable]-secure-setting key` | Enables/disables the given secure setting for current user. This will generate a UAC prompt | 3.2.1+ | \*After modifying the settings, you must ensure that any running instance of UniGetUI is restarted for the changes to take effect diff --git a/src/UniGetUI.Core.SecureSettings/SecureSettings.cs b/src/UniGetUI.Core.SecureSettings/SecureSettings.cs new file mode 100644 index 0000000000..a7f784c194 --- /dev/null +++ b/src/UniGetUI.Core.SecureSettings/SecureSettings.cs @@ -0,0 +1,107 @@ +using System.Diagnostics; +using UniGetUI.Core.Data; +using UniGetUI.Core.Tools; + +namespace UniGetUI.Core.SettingsEngine.SecureSettings; + +public static class SecureSettings +{ + private static readonly Dictionary _cache = new(); + + public static class Args + { + public const string ENABLE_FOR_USER = "--enable-secure-setting-for-user"; + public const string DISABLE_FOR_USER = "--disable-secure-setting-for-user"; + } + + public static bool Get(string setting) + { + string purifiedSetting = CoreTools.MakeValidFileName(setting); + if (_cache.TryGetValue(purifiedSetting, out var value)) + { + return value; + } + + string purifiedUser = CoreTools.MakeValidFileName(Environment.UserName); + + var appData = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + var settingsLocation = Path.Join(appData, "UniGetUI\\SecureSettings", purifiedUser); + var settingFile = Path.Join(settingsLocation, purifiedSetting); + + if (!Directory.Exists(settingsLocation)) + { + _cache[purifiedSetting] = false; + return false; + } + + bool exists = File.Exists(settingFile); + _cache[purifiedSetting] = exists; + return exists; + } + + public static async Task TrySet(string setting, bool enabled) + { + string purifiedSetting = CoreTools.MakeValidFileName(setting); + _cache.Remove(purifiedSetting); + + string purifiedUser = CoreTools.MakeValidFileName(Environment.UserName); + + using Process p = new Process(); + p.StartInfo = new() + { + UseShellExecute = true, + CreateNoWindow = true, + FileName = CoreData.UniGetUIExecutableFile, + Verb = "runas", + ArgumentList = + { + enabled? Args.ENABLE_FOR_USER: Args.DISABLE_FOR_USER, + purifiedUser, + purifiedSetting + } + }; + + p.Start(); + await p.WaitForExitAsync(); + return p.ExitCode is 0; + } + + public static int ApplyForUser(string username, string setting, bool enable) + { + try + { + string purifiedSetting = CoreTools.MakeValidFileName(setting); + _cache.Remove(purifiedSetting); + + string purifiedUser = CoreTools.MakeValidFileName(username); + + var appData = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + var settingsLocation = Path.Join(appData, "UniGetUI\\SecureSettings", purifiedUser); + var settingFile = Path.Join(settingsLocation, purifiedSetting); + + if (!Directory.Exists(settingsLocation)) + { + Directory.CreateDirectory(settingsLocation); + } + + if (enable) + { + File.WriteAllText(settingFile, ""); + } + else + { + if (File.Exists(settingFile)) + { + File.Delete(settingFile); + } + } + + return 0; + } + catch (Exception ex) + { + Console.WriteLine(ex); + return -1; + } + } +} diff --git a/src/UniGetUI.Core.SecureSettings/UniGetUI.Core.SecureSettings.csproj b/src/UniGetUI.Core.SecureSettings/UniGetUI.Core.SecureSettings.csproj new file mode 100644 index 0000000000..704c7f08fb --- /dev/null +++ b/src/UniGetUI.Core.SecureSettings/UniGetUI.Core.SecureSettings.csproj @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/InstallOptionsFactory.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/InstallOptionsFactory.cs index b0121b0f46..f244fa64af 100644 --- a/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/InstallOptionsFactory.cs +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Packages/Classes/InstallOptionsFactory.cs @@ -1,13 +1,10 @@ using System.Collections.Concurrent; -using System.Runtime.InteropServices; using System.Text.Json; using System.Text.Json.Nodes; -using ABI.Windows.UI.Text.Core; using UniGetUI.Core.Data; -using UniGetUI.Core.Language; using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine.SecureSettings; using UniGetUI.Core.Tools; -using UniGetUI.PackageEngine.Enums; using UniGetUI.PackageEngine.Interfaces; using UniGetUI.PackageEngine.Serializable; @@ -90,7 +87,7 @@ public static InstallOptions LoadApplicable( if (no_integrity is not null) instance.SkipHashCheck = (bool)no_integrity; if (remove_data is not null) instance.RemoveDataOnUninstall = (bool)remove_data; - return instance; + return EnsureSecureOptions(instance); } /// @@ -112,7 +109,7 @@ public static Task LoadApplicableAsync( bool? no_integrity = null, bool? remove_data = null, InstallOptions? overridePackageOptions = null) - => Task.Run(() => LoadApplicable(package, elevated, interactive, no_integrity, remove_data)); + => Task.Run(() => LoadApplicable(package, elevated, interactive, no_integrity, remove_data, overridePackageOptions)); /* * @@ -186,5 +183,33 @@ private static InstallOptions _loadFromDisk(string key) return new(); } } + + private static InstallOptions EnsureSecureOptions(InstallOptions options) + { + if (SecureSettings.Get("AllowCLIArguments")) + { + // If CLI arguments are allowed, sanitize them + for (int i = 0; i < options.CustomParameters.Count; i++) + { + options.CustomParameters[i] = options.CustomParameters[i] + .Replace("&", "") + .Replace("|", "") + .Replace(";", "") + .Replace("<", "") + .Replace(">", "") + .Replace("\n", ""); + } + } + else + { + // Otherwhise, clear them + if (options.CustomParameters.Count > 0) + Logger.Warn($"Custom CLI parameters [{string.Join(' ', options.CustomParameters)}] will be discarded"); + + options.CustomParameters = []; + } + + return options; + } } } diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/UniGetUI.PackageEngine.Classes.csproj b/src/UniGetUI.PackageEngine.PackageManagerClasses/UniGetUI.PackageEngine.Classes.csproj index ceedce4d0e..7a21a8a0f8 100644 --- a/src/UniGetUI.PackageEngine.PackageManagerClasses/UniGetUI.PackageEngine.Classes.csproj +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/UniGetUI.PackageEngine.Classes.csproj @@ -7,6 +7,7 @@ + diff --git a/src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs b/src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs index 0073e05a5a..82baacad23 100644 --- a/src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs +++ b/src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs @@ -62,22 +62,6 @@ public override void LoadFromJson(JsonNode data) // This entry shall be checked the last one, to ensure all other properties are set this.OverridesNextLevelOpts = data[nameof(OverridesNextLevelOpts)]?.GetValue() ?? DiffersFromDefault(); - - SanitizeOptions(); - } - - private void SanitizeOptions() - { - for (int i = 0; i < this.CustomParameters.Count; i++) - { - this.CustomParameters[i] = this.CustomParameters[i] - .Replace("&", "") - .Replace("|", "") - .Replace(";", "") - .Replace("<", "") - .Replace(">", "") - .Replace("\n", ""); - } } public bool DiffersFromDefault() diff --git a/src/UniGetUI.sln b/src/UniGetUI.sln index 7324d653bb..d71e0676e3 100644 --- a/src/UniGetUI.sln +++ b/src/UniGetUI.sln @@ -105,6 +105,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{015B44EE EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniGetUI.PackageEngine.Serializable.Tests", "UniGetUI.PackageEngine.Serializable.Tests\UniGetUI.PackageEngine.Serializable.Tests.csproj", "{F1610A61-5444-4C11-9447-13CCA327887E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniGetUI.Core.SecureSettings", "UniGetUI.Core.SecureSettings\UniGetUI.Core.SecureSettings.csproj", "{B0E59327-933E-4DB0-BD2D-FB16EB9B4194}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -271,6 +273,10 @@ Global {F1610A61-5444-4C11-9447-13CCA327887E}.Debug|x64.Build.0 = Debug|x64 {F1610A61-5444-4C11-9447-13CCA327887E}.Release|x64.ActiveCfg = Release|x64 {F1610A61-5444-4C11-9447-13CCA327887E}.Release|x64.Build.0 = Release|x64 + {B0E59327-933E-4DB0-BD2D-FB16EB9B4194}.Debug|x64.ActiveCfg = Debug|x64 + {B0E59327-933E-4DB0-BD2D-FB16EB9B4194}.Debug|x64.Build.0 = Debug|x64 + {B0E59327-933E-4DB0-BD2D-FB16EB9B4194}.Release|x64.ActiveCfg = Release|x64 + {B0E59327-933E-4DB0-BD2D-FB16EB9B4194}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -319,6 +325,7 @@ Global {3C8BF564-B4B5-44A7-9D8C-102C2F820EAF} = {8CF74C87-534F-4017-A4ED-F2918025E31A} {015B44EE-32AE-4105-9016-49140743CAF9} = {7940E867-EEBA-4AFD-9904-1536F003239C} {F1610A61-5444-4C11-9447-13CCA327887E} = {015B44EE-32AE-4105-9016-49140743CAF9} + {B0E59327-933E-4DB0-BD2D-FB16EB9B4194} = {E05D1183-D360-4AFE-8968-314A34FAD3B2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D044BB14-0B37-47E5-A579-8B30FCBA1F9F} diff --git a/src/UniGetUI/CLIHandler.cs b/src/UniGetUI/CLIHandler.cs index 797e9316a8..d917e4e259 100644 --- a/src/UniGetUI/CLIHandler.cs +++ b/src/UniGetUI/CLIHandler.cs @@ -1,5 +1,6 @@ using UniGetUI.Core.Logging; using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; namespace UniGetUI; @@ -19,10 +20,16 @@ public static class CLIHandler public const string DISABLE_SETTING = "--disable-setting"; public const string SET_SETTING_VAL = "--set-setting-value"; + public const string ENABLE_SECURE_SETTING = "--enable-secure-setting"; + public const string DISABLE_SECURE_SETTING = "--disable-secure-setting"; + public const string ENABLE_SECURE_SETTING_FOR_USER = SecureSettings.Args.ENABLE_FOR_USER; + public const string DISABLE_SECURE_SETTING_FOR_USER = SecureSettings.Args.DISABLE_FOR_USER; + private enum HRESULT { - SUCCESS = 0x00000000, + SUCCESS = 0, + STATUS_FAILED = -1, STATUS_INVALID_PARAMETER = -1073741811, STATUS_NO_SUCH_FILE = -1073741809, } @@ -48,7 +55,7 @@ public static int ImportSettings() if (filePos +1 >= args.Count) return (int)HRESULT.STATUS_INVALID_PARAMETER; // The file parameter does not exist (import settings requires "--import-settings file") - var file = args[filePos + 1].Replace("\"", "").Replace("\'", ""); + var file = args[filePos + 1].Trim('"').Trim('\''); if (!File.Exists(file)) return (int)HRESULT.STATUS_NO_SUCH_FILE; // The given file does not exist @@ -75,7 +82,7 @@ public static int ExportSettings() if (filePos +1 >= args.Count) return (int)HRESULT.STATUS_INVALID_PARAMETER; // The file parameter does not exist (export settings requires "--export-settings file") - var file = args[filePos + 1].Replace("\"", "").Replace("\'", ""); + var file = args[filePos + 1].Trim('"').Trim('\''); try { @@ -100,7 +107,7 @@ public static int EnableSetting() if (basePos +1 >= args.Count) return (int)HRESULT.STATUS_INVALID_PARAMETER; // The file parameter does not exist (export settings requires "--export-settings file") - var setting = args[basePos + 1].Replace("\"", "").Replace("\'", ""); + var setting = args[basePos + 1].Trim('"').Trim('\''); try { @@ -125,7 +132,7 @@ public static int DisableSetting() if (basePos +1 >= args.Count) return (int)HRESULT.STATUS_INVALID_PARAMETER; // The file parameter does not exist (export settings requires "--export-settings file") - var setting = args[basePos + 1].Replace("\"", "").Replace("\'", ""); + var setting = args[basePos + 1].Trim('"').Trim('\''); try { @@ -150,7 +157,7 @@ public static int SetSettingsValue() if (basePos +2 >= args.Count) return (int)HRESULT.STATUS_INVALID_PARAMETER; // The file parameter does not exist (export settings requires "--export-settings file") - var setting = args[basePos + 1].Replace("\"", "").Replace("\'", ""); + var setting = args[basePos + 1].Trim('"').Trim('\''); var value = args[basePos + 2]; try @@ -230,4 +237,102 @@ public static int UninstallUniGetUI() // There is currently no uninstall logic. However, this needs to be maintained, or otherwhise UniGetUI will launch on uninstall return 0; } + + public static int EnableSecureSetting() + { + var args = Environment.GetCommandLineArgs().ToList(); + + var basePos = args.IndexOf(ENABLE_SECURE_SETTING); + if (basePos < 0) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The base paramater was not found + + if (basePos +1 >= args.Count) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The file parameter does not exist (export settings requires "--export-settings file") + + var setting = args[basePos + 1].Trim('"').Trim('\''); + + try + { + bool success = SecureSettings.TrySet(setting, true).GetAwaiter().GetResult(); + if (!success) return (int)HRESULT.STATUS_FAILED; + else return (int)HRESULT.SUCCESS; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int DisableSecureSetting() + { + var args = Environment.GetCommandLineArgs().ToList(); + + var basePos = args.IndexOf(DISABLE_SECURE_SETTING); + if (basePos < 0) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The base paramater was not found + + if (basePos +1 >= args.Count) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The first positional argument does not exist + + var setting = args[basePos + 1].Trim('"').Trim('\''); + + try + { + bool success = SecureSettings.TrySet(setting, false).GetAwaiter().GetResult(); + if (!success) return (int)HRESULT.STATUS_FAILED; + else return (int)HRESULT.SUCCESS; + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int EnableSecureSettingForUser() + { + var args = Environment.GetCommandLineArgs().ToList(); + + var basePos = args.IndexOf(ENABLE_SECURE_SETTING_FOR_USER); + if (basePos < 0) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The base paramater was not found + + if (basePos +2 >= args.Count) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The required parameters do not exist + + var user = args[basePos + 1].Trim('"').Trim('\''); + var setting = args[basePos + 2].Trim('"').Trim('\''); + + try + { + return SecureSettings.ApplyForUser(user, setting, true); + } + catch (Exception ex) + { + return ex.HResult; + } + } + + public static int DisableSecureSettingForUser() + { + var args = Environment.GetCommandLineArgs().ToList(); + + var basePos = args.IndexOf(DISABLE_SECURE_SETTING_FOR_USER); + if (basePos < 0) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The base paramater was not found + + if (basePos +2 >= args.Count) + return (int)HRESULT.STATUS_INVALID_PARAMETER; // The required parameters do not exist + + var user = args[basePos + 1].Trim('"').Trim('\''); + var setting = args[basePos + 2].Trim('"').Trim('\''); + + try + { + return SecureSettings.ApplyForUser(user, setting, false); + } + catch (Exception ex) + { + return ex.HResult; + } + } } diff --git a/src/UniGetUI/Controls/SettingsWidgets/CheckboxCard.cs b/src/UniGetUI/Controls/SettingsWidgets/CheckboxCard.cs index 5ee7ddcf05..c86d2a2208 100644 --- a/src/UniGetUI/Controls/SettingsWidgets/CheckboxCard.cs +++ b/src/UniGetUI/Controls/SettingsWidgets/CheckboxCard.cs @@ -1,6 +1,7 @@ using CommunityToolkit.WinUI.Controls; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; using UniGetUI.Core.SettingsEngine; using UniGetUI.Core.Tools; @@ -13,6 +14,7 @@ public partial class CheckboxCard : SettingsCard { public ToggleSwitch _checkbox; public TextBlock _textblock; + public TextBlock _warningBlock; protected bool IS_INVERTED; protected string setting_name = ""; @@ -40,6 +42,20 @@ public string Text set => _textblock.Text = CoreTools.Translate(value); } + public string WarningText + { + set + { + _warningBlock.Text = CoreTools.Translate(value); + _warningBlock.Visibility = value.Any() ? Visibility.Visible : Visibility.Collapsed; + } + } + + public Brush WarningForeground + { + set => _warningBlock.Foreground = value; + } + public CheckboxCard() { _checkbox = new ToggleSwitch() @@ -52,9 +68,22 @@ public CheckboxCard() Margin = new Thickness(0, 0, 0, 0), TextWrapping = TextWrapping.Wrap }; + _warningBlock = new TextBlock() + { + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 0, 0), + TextWrapping = TextWrapping.Wrap, + FontSize = 12, + Visibility = Visibility.Collapsed, + }; IS_INVERTED = false; Content = _checkbox; - Header = _textblock; + Header = new StackPanel() + { + Spacing = 4, + Orientation = Orientation.Vertical, + Children = { _textblock, _warningBlock } + }; _checkbox.HorizontalAlignment = HorizontalAlignment.Stretch; _checkbox.Toggled += _checkbox_Toggled; diff --git a/src/UniGetUI/Controls/SettingsWidgets/SecureCheckboxCard.cs b/src/UniGetUI/Controls/SettingsWidgets/SecureCheckboxCard.cs new file mode 100644 index 0000000000..cb15b53771 --- /dev/null +++ b/src/UniGetUI/Controls/SettingsWidgets/SecureCheckboxCard.cs @@ -0,0 +1,134 @@ +using CommunityToolkit.WinUI.Controls; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Core.Tools; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace UniGetUI.Interface.Widgets +{ + public partial class SecureCheckboxCard : SettingsCard + { + public ToggleSwitch _checkbox; + public TextBlock _textblock; + public TextBlock _warningBlock; + public ProgressRing _loading; + protected bool IS_INVERTED; + + protected string setting_name = ""; + public virtual string SettingName + { + set + { + _checkbox.IsEnabled = false; + setting_name = value; + IS_INVERTED = value.StartsWith("Disable"); + _checkbox.IsOn = SecureSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + _textblock.Opacity = _checkbox.IsOn ? 1 : 0.7; + _checkbox.IsEnabled = true; + } + } + + public new bool IsEnabled + { + set + { + base.IsEnabled = value; + _warningBlock.Opacity = value ? 1 : 0.2; + } + get => base.IsEnabled; + } + + public bool ForceInversion { get; set; } + + public bool Checked + { + get => _checkbox.IsOn; + } + public virtual event EventHandler? StateChanged; + + public string Text + { + set => _textblock.Text = CoreTools.Translate(value); + } + + public string WarningText + { + set + { + _warningBlock.Text = CoreTools.Translate(value); + _warningBlock.Visibility = value.Any() ? Visibility.Visible : Visibility.Collapsed; + } + } + + public SecureCheckboxCard() + { + _checkbox = new ToggleSwitch() + { + Margin = new Thickness(0, 0, 8, 0) + }; + + _loading = new ProgressRing() { IsIndeterminate = true, Visibility = Visibility.Collapsed}; + _textblock = new TextBlock() + { + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 0, 0), + TextWrapping = TextWrapping.Wrap + }; + _warningBlock = new TextBlock() + { + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 0, 0), + TextWrapping = TextWrapping.Wrap, + Foreground = (SolidColorBrush)Application.Current.Resources["SystemControlErrorTextForegroundBrush"], + FontSize = 12, + Visibility = Visibility.Collapsed, + }; + IS_INVERTED = false; + Content = new StackPanel() + { + Spacing = 4, + Orientation = Orientation.Horizontal, + Children = { _loading, _checkbox }, + }; + //Header = _textblock; + Header = new StackPanel() + { + Spacing = 4, + Orientation = Orientation.Vertical, + Children = { _textblock, _warningBlock } + }; + + _checkbox.HorizontalAlignment = HorizontalAlignment.Stretch; + _checkbox.Toggled += (s, e) => _ = _checkbox_Toggled(); + } + protected virtual async Task _checkbox_Toggled() + { + try + { + if (_checkbox.IsEnabled is false) + return; + + _loading.Visibility = Visibility.Visible; + _checkbox.IsEnabled = false; + StateChanged?.Invoke(this, EventArgs.Empty); + await SecureSettings.TrySet(setting_name, _checkbox.IsOn ^ IS_INVERTED ^ ForceInversion); + _textblock.Opacity = _checkbox.IsOn ? 1 : 0.7; + _checkbox.IsOn = SecureSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + _loading.Visibility = Visibility.Collapsed; + _checkbox.IsEnabled = true; + } + catch (Exception ex) + { + Logger.Warn(ex); + _checkbox.IsOn = SecureSettings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + _loading.Visibility = Visibility.Collapsed; + _checkbox.IsEnabled = true; + } + } + } +} diff --git a/src/UniGetUI/EntryPoint.cs b/src/UniGetUI/EntryPoint.cs index d0ef2999f4..20514ed893 100644 --- a/src/UniGetUI/EntryPoint.cs +++ b/src/UniGetUI/EntryPoint.cs @@ -55,6 +55,26 @@ private static void Main(string[] args) int ret = CLIHandler.SetSettingsValue(); Environment.Exit(ret); } + else if (args.Contains(CLIHandler.ENABLE_SECURE_SETTING)) + { + int ret = CLIHandler.EnableSecureSetting(); + Environment.Exit(ret); + } + else if (args.Contains(CLIHandler.DISABLE_SECURE_SETTING)) + { + int ret = CLIHandler.DisableSecureSetting(); + Environment.Exit(ret); + } + else if (args.Contains(CLIHandler.ENABLE_SECURE_SETTING_FOR_USER)) + { + int ret = CLIHandler.EnableSecureSettingForUser(); + Environment.Exit(ret); + } + else if (args.Contains(CLIHandler.DISABLE_SECURE_SETTING_FOR_USER)) + { + int ret = CLIHandler.DisableSecureSettingForUser(); + Environment.Exit(ret); + } else { CoreData.WasDaemon = CoreData.IsDaemon = args.Contains(CLIHandler.DAEMON); diff --git a/src/UniGetUI/Pages/DialogPages/InstallOptions_Package.xaml.cs b/src/UniGetUI/Pages/DialogPages/InstallOptions_Package.xaml.cs index dcb35a8d6d..f99a5fa432 100644 --- a/src/UniGetUI/Pages/DialogPages/InstallOptions_Package.xaml.cs +++ b/src/UniGetUI/Pages/DialogPages/InstallOptions_Package.xaml.cs @@ -315,10 +315,10 @@ private async void GenerateCommand() { if (!_uiLoaded) return; InstallOptions options = await GetUpdatedOptions(updateIgnoredUpdates: false); - if (!options.OverridesNextLevelOpts) - { - options = await InstallOptionsFactory.LoadApplicableAsync(this.Package, overridePackageOptions: options); - } + //if (!options.OverridesNextLevelOpts) + //{ + options = await InstallOptionsFactory.LoadApplicableAsync(this.Package, overridePackageOptions: options); + //} var op = ProfileComboBox.SelectedIndex switch { diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml index a0d931e0aa..b8e79fed1a 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml @@ -25,6 +25,13 @@ VerticalContentAlignment="Center"> + + + Text="Ask only once for administrator privileges" /> + + + + + + + + diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs index d1cdc3268b..81aa4dda69 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs @@ -20,10 +20,19 @@ public Administrator() DoCacheAdminRights.IsEnabled = true; DoCacheAdminRightsForBatches.IsEnabled = true; } + + WarningTitlebar.Title = CoreTools.Translate("Warning") + "!"; + WarningTitlebar.Message = + CoreTools.Translate("The following settings may pose a security risk, hence they are disabled by default.") + " " + + CoreTools.Translate("Enable the settings below if and only if you fully understand what they do, and the implications they may have.") + "\n\n" + + CoreTools.Translate("The settings will list, in their descriptions, the potential security issues they may have.") + " "; + + // The following settings may pose a security risk, hence they are disabled by default. Enable them ONLY if you undertsand what you are doing. Some of those settings will show a UAC prompt before being enabled." + } public bool CanGoBack => true; - public string ShortTitle => CoreTools.Translate("Administrator privileges preferences"); + public string ShortTitle => CoreTools.Translate("Administrator rights and other dangerous settings"); public event EventHandler? RestartRequired; public event EventHandler? NavigationRequested; diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Experimental.xaml b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Experimental.xaml index d49e1bc3d7..56a60ca9f2 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Experimental.xaml +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Experimental.xaml @@ -44,6 +44,7 @@ StateChanged="ShowRestartBanner" Text="Wait for the device to be connected to the internet before attempting to do tasks that require internet connectivity." /> + - + Text="Use installed GSudo instead of the bundled one" / + --> @@ -91,6 +94,8 @@ CornerRadius="8" SettingName="DisableDMWThreadOptimizations" Text="Enable background CPU Usage optimizations (see Pull Request #3278)" /> + + diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Operations.xaml b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Operations.xaml index bb3ba1cead..8d0ff4d959 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Operations.xaml +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Operations.xaml @@ -80,10 +80,10 @@ CornerRadius="0,0,8,8" IsClickEnabled="True"> - + - + diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml b/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml index d8407f0759..92c4cf3935 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml @@ -57,14 +57,13 @@ UnderText="Show notifications on different events" /> - + Icon="uac" + Text="Administrator rights and other dangerous settings" + UnderText="Reduce UAC prompts, elevate installations by default, unlock certain dangerous features, etc." /> @@ -88,32 +87,46 @@ + Icon="disk" + Text="Package backup" + UnderText="Automatically save a list of all your installed packages to easily restore them." /> + + Text="Package manager preferences" + UnderText="Enable and disable package managers, change default install options, etc."> - + + + + + + + diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml.cs b/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml.cs index c67633179f..93b02aad7f 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml.cs +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/SettingsHomepage.xaml.cs @@ -33,6 +33,6 @@ public SettingsHomepage() public void Operations(object s, RoutedEventArgs e) => NavigationRequested?.Invoke(this, typeof(Operations)); public void Startup(object s, RoutedEventArgs e) => NavigationRequested?.Invoke(this, typeof(Updates)); private void Internet(object sender, RoutedEventArgs e) => NavigationRequested?.Invoke(this, typeof(Internet)); - + private void ManagersShortcut(object sender, RoutedEventArgs e) => NavigationRequested?.Invoke(this, typeof(ManagersHomepage)); } } diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Updates.xaml b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Updates.xaml index ee88bb42fb..ef683a930d 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Updates.xaml +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Updates.xaml @@ -74,9 +74,9 @@ Text="Related settings" /> @@ -94,10 +94,10 @@ CornerRadius="0,0,8,8" IsClickEnabled="True"> - + - + diff --git a/src/UniGetUI/Pages/SettingsPages/SettingsBasePage.xaml.cs b/src/UniGetUI/Pages/SettingsPages/SettingsBasePage.xaml.cs index 81f42b1356..17f093a3e4 100644 --- a/src/UniGetUI/Pages/SettingsPages/SettingsBasePage.xaml.cs +++ b/src/UniGetUI/Pages/SettingsPages/SettingsBasePage.xaml.cs @@ -82,6 +82,10 @@ private void Page_RestartRequired(object? sender, EventArgs e) private void Page_NavigationRequested(object? sender, Type e) { + if(e == typeof(ManagersHomepage)) + { + MainApp.Instance.MainWindow.NavigationPage.NavigateTo(Interface.PageType.Managers); + } if(e.IsSubclassOf(typeof(PackageManager))) { MainNavigationFrame.Navigate(typeof(PackageManagerPage), e, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight} ); diff --git a/src/UniGetUI/Properties/launchSettings.json b/src/UniGetUI/Properties/launchSettings.json index 4c8375a637..7108a3ce55 100644 --- a/src/UniGetUI/Properties/launchSettings.json +++ b/src/UniGetUI/Properties/launchSettings.json @@ -4,7 +4,8 @@ "commandName": "MsixPackage" }, "UniGetUI (Unpackaged)": { - "commandName": "Project" + "commandName": "Project", + "commandLineArgs": "" } } } diff --git a/src/UniGetUI/UniGetUI.csproj b/src/UniGetUI/UniGetUI.csproj index 6856170f51..9a3c1c3188 100644 --- a/src/UniGetUI/UniGetUI.csproj +++ b/src/UniGetUI/UniGetUI.csproj @@ -270,6 +270,7 @@ +