diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a04018c31..2f700f481 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,6 +35,7 @@ jobs: key: ${{ runner.os }}-tools-${{ hashFiles('recipe.cake') }} - name: Build project + shell: powershell run: | ./build.ps1 --target=CI diff --git a/.templates/default/issue-note.sbn b/.templates/default/issue-note.sbn index 10c10a97d..03dc65196 100644 --- a/.templates/default/issue-note.sbn +++ b/.templates/default/issue-note.sbn @@ -1,6 +1,6 @@ {{ if issue_label == "Bug" || issue_label == "Bug Fix" || issue_label == "Bug Fixes" -}}- Fix - {{ issue.title }} - see [#{{ issue.number }}]({{ issue.html_url }}). +}}- Fix - {{ issue.title }} - see [#{{ issue.public_number }}]({{ issue.html_url }}). {{ else -}}- {{ issue.title }} - see [#{{ issue.number }}]({{ issue.html_url }}). +}}- {{ issue.title }} - see [#{{ issue.public_number }}]({{ issue.html_url }}). {{ end -}} diff --git a/.templates/default/release-info.sbn b/.templates/default/release-info.sbn index 8410ca5ad..2b495d213 100644 --- a/.templates/default/release-info.sbn +++ b/.templates/default/release-info.sbn @@ -1,9 +1,9 @@ {{ if issues.count > 0 if commits.count > 0 -}}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}) which resulted in [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?closed=1) being closed. +}}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}) which resulted in [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?{{ milestone.query_string }}) being closed. {{ else -}}As part of this release we had [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?closed=1) closed. +}}As part of this release we had [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?{{ milestone.query_string }}) closed. {{ end else if commits.count > 0 }}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}). diff --git a/Source/ChocolateyGui.Common.Windows/Services/ChocolateyService.cs b/Source/ChocolateyGui.Common.Windows/Services/ChocolateyService.cs index 86058ab6e..f848f5d9d 100644 --- a/Source/ChocolateyGui.Common.Windows/Services/ChocolateyService.cs +++ b/Source/ChocolateyGui.Common.Windows/Services/ChocolateyService.cs @@ -47,8 +47,7 @@ public class ChocolateyService : IChocolateyService private readonly IConfigService _configService; private GetChocolatey _choco; private string _localAppDataPath = string.Empty; -#pragma warning disable SA1401 // Fields must be private -#pragma warning restore SA1401 // Fields must be private + private const string ErrorRegex = "^\\s*(ERROR|FATAL|WARN)"; public ChocolateyService(IMapper mapper, IProgressService progressService, IChocolateyConfigSettingsService configSettingsService, IXmlService xmlService, IFileSystem fileSystem, IConfigService configService) { @@ -677,6 +676,13 @@ private static List GetErrors(out Action grabErrors) case LogLevel.Error: case LogLevel.Fatal: errors.Add(m.Message); + break; + case LogLevel.Info: + if (System.Text.RegularExpressions.Regex.IsMatch(m.Message, ErrorRegex)) + { + errors.Add(m.Message); + } + break; } }; diff --git a/Source/ChocolateyGui.Common.Windows/Startup/ChocolateyGuiModule.cs b/Source/ChocolateyGui.Common.Windows/Startup/ChocolateyGuiModule.cs index ec8f01a30..1694ebd0f 100644 --- a/Source/ChocolateyGui.Common.Windows/Startup/ChocolateyGuiModule.cs +++ b/Source/ChocolateyGui.Common.Windows/Startup/ChocolateyGuiModule.cs @@ -148,13 +148,22 @@ protected override void Load(ContainerBuilder builder) var userDatabase = new LiteDatabase($"filename={Path.Combine(Bootstrapper.LocalAppDataPath, "data.db")};upgrade=true"); LiteDatabase globalDatabase; + var globalConfigDirectory = Path.Combine(Bootstrapper.AppDataPath, "Config"); + var globalConfigDatabaseFile = Path.Combine(globalConfigDirectory, "data.db"); + if (Hacks.IsElevated) { - globalDatabase = new LiteDatabase($"filename={Path.Combine(Bootstrapper.AppDataPath, "Config", "data.db")};upgrade=true"); + if (!Directory.Exists(globalConfigDirectory)) + { + Directory.CreateDirectory(globalConfigDirectory); + Hacks.LockDirectory(globalConfigDirectory); + } + + globalDatabase = new LiteDatabase($"filename={globalConfigDatabaseFile};upgrade=true"); } else { - if (!File.Exists(Path.Combine(Bootstrapper.AppDataPath, "Config", "data.db"))) + if (!File.Exists(globalConfigDatabaseFile)) { // Since the global configuration database file doesn't exist, we must be running in a state where an administrator user // has never run Chocolatey GUI. In this case, use null, which will mean attempts to use the global database will be ignored. @@ -163,7 +172,7 @@ protected override void Load(ContainerBuilder builder) else { // Since this is a non-administrator user, they should only have read permissions to this database - globalDatabase = new LiteDatabase($"filename={Path.Combine(Bootstrapper.AppDataPath, "Config", "data.db")};readonly=true"); + globalDatabase = new LiteDatabase($"filename={globalConfigDatabaseFile};readonly=true"); } } diff --git a/Source/ChocolateyGui.Common/Hacks.cs b/Source/ChocolateyGui.Common/Hacks.cs index 3f147b778..1e32e621d 100644 --- a/Source/ChocolateyGui.Common/Hacks.cs +++ b/Source/ChocolateyGui.Common/Hacks.cs @@ -5,6 +5,9 @@ // // -------------------------------------------------------------------------------------------------------------------- +using System; +using System.IO; +using System.Security.AccessControl; using System.Security.Principal; namespace ChocolateyGui.Common @@ -12,5 +15,33 @@ namespace ChocolateyGui.Common public static class Hacks { public static bool IsElevated => (WindowsIdentity.GetCurrent().Owner?.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid)).GetValueOrDefault(false); + + // TODO: Replace this LockDirectory with calls to DotNetFileSystem's LockDirectory when https://github.com/chocolatey/ChocolateyGUI/issues/1046 is completed. + /// + /// Lock the given directory path to just Administrators being able to write. This method is copied from chocolatey.infrastructure.filesystem.DotNetFileSystem, and should be replaced with that call when the minimum Chocolatey.lib is bumped to 2.2.0 or greater. + /// + /// Directory path to lock down. + public static void LockDirectory(string directoryPath) + { + var permissions = Directory.GetAccessControl(directoryPath); + var rules = permissions.GetAccessRules(includeExplicit: true, includeInherited: true, targetType: typeof(NTAccount)); + + // We first need to remove all rules + foreach (FileSystemAccessRule rule in rules) + { + permissions.RemoveAccessRuleAll(rule); + } + + var bultinAdmins = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).Translate(typeof(NTAccount)); + var localsystem = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)); + var builtinUsers = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null).Translate(typeof(NTAccount)); + var inheritanceFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit; + permissions.SetAccessRule(new FileSystemAccessRule(bultinAdmins, FileSystemRights.FullControl, inheritanceFlags, PropagationFlags.None, AccessControlType.Allow)); + permissions.SetAccessRule(new FileSystemAccessRule(localsystem, FileSystemRights.FullControl, inheritanceFlags, PropagationFlags.None, AccessControlType.Allow)); + permissions.SetAccessRule(new FileSystemAccessRule(builtinUsers, FileSystemRights.ReadAndExecute, inheritanceFlags, PropagationFlags.None, AccessControlType.Allow)); + permissions.SetOwner(bultinAdmins); + permissions.SetAccessRuleProtection(isProtected: true, preserveInheritance: false); + Directory.SetAccessControl(directoryPath, permissions); + } } } \ No newline at end of file diff --git a/Source/ChocolateyGuiCli/Startup/ChocolateyGuiCliModule.cs b/Source/ChocolateyGuiCli/Startup/ChocolateyGuiCliModule.cs index 0dc97e388..8d952ad1d 100644 --- a/Source/ChocolateyGuiCli/Startup/ChocolateyGuiCliModule.cs +++ b/Source/ChocolateyGuiCli/Startup/ChocolateyGuiCliModule.cs @@ -48,13 +48,22 @@ protected override void Load(ContainerBuilder builder) var userDatabase = new LiteDatabase($"filename={Path.Combine(Bootstrapper.LocalAppDataPath, "data.db")};upgrade=true"); LiteDatabase globalDatabase; + var globalConfigDirectory = Path.Combine(Bootstrapper.AppDataPath, "Config"); + var globalConfigDatabaseFile = Path.Combine(globalConfigDirectory, "data.db"); + if (Hacks.IsElevated) { - globalDatabase = new LiteDatabase($"filename={Path.Combine(Bootstrapper.AppDataPath, "Config", "data.db")};upgrade=true"); + if (!Directory.Exists(globalConfigDirectory)) + { + Directory.CreateDirectory(globalConfigDirectory); + Hacks.LockDirectory(globalConfigDirectory); + } + + globalDatabase = new LiteDatabase($"filename={globalConfigDatabaseFile};upgrade=true"); } else { - if (!File.Exists(Path.Combine(Bootstrapper.AppDataPath, "Config", "data.db"))) + if (!File.Exists(globalConfigDatabaseFile)) { // Since the global configuration database file doesn't exist, we must be running in a state where an administrator user // has never run Chocolatey GUI. In this case, use null, which will mean attempts to use the global database will be ignored. @@ -63,7 +72,7 @@ protected override void Load(ContainerBuilder builder) else { // Since this is a non-administrator user, they should only have read permissions to this database - globalDatabase = new LiteDatabase($"filename={Path.Combine(Bootstrapper.AppDataPath, "Config", "data.db")};readonly=true"); + globalDatabase = new LiteDatabase($"filename={globalConfigDatabaseFile};readonly=true"); } } diff --git a/recipe.cake b/recipe.cake index 10b99d3ff..b619ebd9a 100644 --- a/recipe.cake +++ b/recipe.cake @@ -1,4 +1,4 @@ -#load nuget:?package=Chocolatey.Cake.Recipe&version=0.23.0 +#load nuget:?package=Chocolatey.Cake.Recipe&version=0.27.0 /////////////////////////////////////////////////////////////////////////////// // MODULES @@ -13,7 +13,7 @@ if (BuildSystem.IsLocalBuild) { Environment.SetVariableNames( - gitHubTokenVariable: "CHOCOLATEYGUI_GITHUB_PAT", + gitReleaseManagerTokenVariable: "CHOCOLATEYGUI_GITHUB_PAT", transifexApiTokenVariable: "CHOCOLATEYGUI_TRANSIFEX_API_TOKEN" ); }