Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .deepsource.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ enabled = false # Disables standardjs transformer

[[transformers]]
name = "prettier"
enabled = false # Disables prettier transformer
enabled = false # Disables prettier transformer
5 changes: 3 additions & 2 deletions cli-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
107 changes: 107 additions & 0 deletions src/UniGetUI.Core.SecureSettings/SecureSettings.cs
Original file line number Diff line number Diff line change
@@ -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<string, bool> _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<bool> 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;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\UniGetUI.Core.Tools\UniGetUI.Core.Tools.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\SharedAssemblyInfo.cs" Link="SharedAssemblyInfo.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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);
}

/// <summary>
Expand All @@ -112,7 +109,7 @@ public static Task<InstallOptions> 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));

/*
*
Expand Down Expand Up @@ -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 = [];
Copy link

Copilot AI Jun 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assignment 'options.CustomParameters = [];' may cause issues if CustomParameters is not of an array type; consider using an appropriate collection initializer (e.g., new List()) to match its declared type.

Copilot uses AI. Check for mistakes.
}

return options;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<ProjectReference Include="..\UniGetUI.Core.Data\UniGetUI.Core.Data.csproj" />
<ProjectReference Include="..\UniGetUI.Core.IconStore\UniGetUI.Core.IconEngine.csproj" />
<ProjectReference Include="..\UniGetUI.Core.LanguageEngine\UniGetUI.Core.LanguageEngine.csproj" />
<ProjectReference Include="..\UniGetUI.Core.SecureSettings\UniGetUI.Core.SecureSettings.csproj" />
<ProjectReference Include="..\UniGetUI.Core.Settings\UniGetUI.Core.Settings.csproj" />
<ProjectReference Include="..\UniGetUI.Core.Tools\UniGetUI.Core.Tools.csproj" />
<ProjectReference Include="..\UniGetUI.PackageEngine.Enums\UniGetUI.PackageEngine.Structs.csproj" />
Expand Down
16 changes: 0 additions & 16 deletions src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool>() ?? 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()
Expand Down
7 changes: 7 additions & 0 deletions src/UniGetUI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
Loading
Loading