mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-16 05:19:23 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b455c89ddc | ||
|
|
782b76cd8e | ||
|
|
230c2d9457 | ||
|
|
63531e3b8c | ||
|
|
ac430305f4 |
@@ -52,7 +52,7 @@ jobs:
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.202'
|
||||
dotnet-version: '6.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
@@ -70,11 +70,16 @@ jobs:
|
||||
$version = .\Scripts\GetBuildVersion.ps1
|
||||
echo "::set-env name=Version::$version"
|
||||
|
||||
- name: Create publish files
|
||||
- name: Create publish launcher files
|
||||
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish installer files
|
||||
run: dotnet publish .\Daybreak.Installer\Daybreak.Installer.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Pack publish files
|
||||
run: |
|
||||
Write-Host $env
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.202'
|
||||
dotnet-version: '6.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,41 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
|
||||
const string tempFile = "tempfile.zip";
|
||||
const string executableName = "Daybreak.exe";
|
||||
Console.Title = "Daybreak Installer";
|
||||
Console.WriteLine("Starting installation...");
|
||||
if (File.Exists(tempFile) is false)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("Unable to find launcher package. Aborting installation");
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Unpacking files...");
|
||||
try
|
||||
{
|
||||
ZipFile.ExtractToDirectory(tempFile, AppContext.BaseDirectory, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
Console.WriteLine("Deleting package");
|
||||
File.Delete(tempFile);
|
||||
Console.WriteLine("Launching application");
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = executableName
|
||||
}
|
||||
};
|
||||
|
||||
if (process.Start() is false)
|
||||
{
|
||||
Console.WriteLine("Failed to launch application");
|
||||
Console.ReadKey();
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.0.0-alpha0002" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0-preview-20220707-01" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+18
-2
@@ -1,12 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31005.135
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32616.157
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak", "Daybreak\Daybreak.csproj", "{AA45C2B1-8BD0-466C-9271-699F168905AF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Daybreak.Tests", "Daybreak.Tests\Daybreak.Tests.csproj", "{C911C1C2-6566-419C-89C7-F802EB3FE709}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pipelines", "Pipelines", "{067BF93F-E5B2-4E99-886E-039C04F35EAB}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.github\workflows\cd.yaml = .github\workflows\cd.yaml
|
||||
.github\workflows\ci.yaml = .github\workflows\ci.yaml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Daybreak.Installer", "Daybreak.Installer\Daybreak.Installer.csproj", "{4E2BB805-135D-4F02-8C53-3D8B6876D323}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -31,6 +39,14 @@ Global
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Behaviors
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace Daybreak.Behaviors
|
||||
{
|
||||
|
||||
@@ -20,7 +20,8 @@ using System.Extensions;
|
||||
using System.Net.Http;
|
||||
using LiteDB;
|
||||
using Daybreak.Services.Options;
|
||||
using System.Http;
|
||||
using Daybreak.Models;
|
||||
using Microsoft.CorrelationVector;
|
||||
|
||||
namespace Daybreak.Configuration
|
||||
{
|
||||
@@ -30,15 +31,13 @@ namespace Daybreak.Configuration
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterResolver(
|
||||
new HttpClientResolver()
|
||||
.WithHttpMessageHandlerFactory((serviceProvider, categoryType) =>
|
||||
{
|
||||
var loggerType = typeof(ILogger<>).MakeGenericType(categoryType);
|
||||
var logger = serviceProvider.GetService(loggerType).As<ILogger>();
|
||||
var handler = new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
|
||||
return handler;
|
||||
}));
|
||||
serviceManager.RegisterHttpFactory((serviceProvider, categoryType) =>
|
||||
{
|
||||
var loggerType = typeof(ILogger<>).MakeGenericType(categoryType);
|
||||
var logger = serviceProvider.GetService(loggerType).As<ILogger>();
|
||||
var handler = new LoggingHttpMessageHandler(logger) { InnerHandler = new HttpClientHandler() };
|
||||
return handler;
|
||||
});
|
||||
serviceManager.RegisterOptionsManager<ApplicationConfigurationOptionsManager>();
|
||||
}
|
||||
|
||||
@@ -46,7 +45,7 @@ namespace Daybreak.Configuration
|
||||
{
|
||||
serviceProducer.ThrowIfNull(nameof(serviceProducer));
|
||||
|
||||
serviceProducer.RegisterSingleton<ViewManager>();
|
||||
serviceProducer.RegisterSingleton<ViewManager>(registerAllInterfaces: true);
|
||||
serviceProducer.RegisterSingleton<IConfigurationManager, ConfigurationManager>();
|
||||
serviceProducer.RegisterSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
|
||||
serviceProducer.RegisterSingleton<IMutexHandler, MutexHandler>();
|
||||
@@ -61,6 +60,7 @@ namespace Daybreak.Configuration
|
||||
serviceProducer.RegisterScoped<IPrivilegeManager, PrivilegeManager>();
|
||||
serviceProducer.RegisterScoped<IScreenManager, ScreenManager>();
|
||||
serviceProducer.RegisterLogWriter<ILogsManager, JsonLogsManager>();
|
||||
serviceProducer.RegisterScoped((sp) => new ScopeMetadata(new CorrelationVector()));
|
||||
}
|
||||
|
||||
public static void RegisterViews(IViewProducer viewProducer)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
|
||||
xmlns:converters="clr-namespace:Daybreak.Converters"
|
||||
x:Name="_this"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:interactivity="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
|
||||
xmlns:converters="clr-namespace:Daybreak.Converters"
|
||||
mc:Ignorable="d"
|
||||
|
||||
+23
-15
@@ -1,35 +1,35 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0-windows</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<Version>0.9.2.7</Version>
|
||||
<Version>0.9.3.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.10" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.43" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.12" />
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.864.35" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1264.42" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="NReco.Logging.File" Version="1.1.1" />
|
||||
<PackageReference Include="NReco.Logging.File" Version="1.1.5" />
|
||||
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageReference Include="Slim" Version="1.5.1" />
|
||||
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
|
||||
<PackageReference Include="Slim" Version="1.7.3" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.5.0" />
|
||||
<PackageReference Include="WCL" Version="1.0.2" />
|
||||
<PackageReference Include="WpfExtended" Version="0.6.1" />
|
||||
<PackageReference Include="WpfExtended" Version="0.6.2" />
|
||||
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.1" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="1.0.0" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -74,4 +74,12 @@
|
||||
<Exec Command="echo.>$(Version).version" />
|
||||
</Target>
|
||||
|
||||
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
|
||||
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
|
||||
<ItemGroup>
|
||||
<FilteredAnalyzer Include="@(Analyzer->Distinct())" />
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
<Analyzer Include="@(FilteredAnalyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -9,49 +9,45 @@ namespace Daybreak.Models
|
||||
[Serializable]
|
||||
public sealed class SecureString
|
||||
{
|
||||
public static SecureString Empty { get => new SecureString(string.Empty); }
|
||||
public static SecureString Empty { get => new(string.Empty); }
|
||||
|
||||
private byte[] encryptedBytes;
|
||||
private readonly byte[] key;
|
||||
|
||||
private byte[] DecryptedValue
|
||||
{
|
||||
get => encryptedBytes.DecryptBytes(key);
|
||||
set => encryptedBytes = value.EncryptBytes(key);
|
||||
get => this.encryptedBytes.DecryptBytes(key);
|
||||
set => this.encryptedBytes = value.EncryptBytes(key);
|
||||
}
|
||||
[JsonProperty("value")]
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return encryptedBytes.DecryptBytes(key).AsString();
|
||||
return this.encryptedBytes.DecryptBytes(key).AsString();
|
||||
}
|
||||
set
|
||||
{
|
||||
encryptedBytes = value.AsBytes().EncryptBytes(key);
|
||||
this.encryptedBytes = value.AsBytes().EncryptBytes(key);
|
||||
}
|
||||
}
|
||||
private SecureString(byte[] value)
|
||||
{
|
||||
key = new byte[32];
|
||||
using (var crypto = new RNGCryptoServiceProvider())
|
||||
{
|
||||
crypto.GetBytes(key);
|
||||
}
|
||||
this.key = new byte[32];
|
||||
using var crypto = RandomNumberGenerator.Create();
|
||||
crypto.GetBytes(key);
|
||||
this.DecryptedValue = value;
|
||||
}
|
||||
public SecureString(string value)
|
||||
{
|
||||
key = new byte[32];
|
||||
using (var crypto = new RNGCryptoServiceProvider())
|
||||
{
|
||||
crypto.GetBytes(key);
|
||||
}
|
||||
this.key = new byte[32];
|
||||
using var crypto = RandomNumberGenerator.Create();
|
||||
crypto.GetBytes(key);
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value;
|
||||
public static implicit operator SecureString(string s) => new SecureString(s);
|
||||
public static implicit operator SecureString(string s) => new(s);
|
||||
public static SecureString operator +(SecureString ss1, SecureString ss2)
|
||||
{
|
||||
if (ss1 is null) throw new ArgumentNullException(nameof(ss1));
|
||||
@@ -123,12 +119,12 @@ namespace Daybreak.Models
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value.GetHashCode();
|
||||
return this.Value.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
return this.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Http;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.Bloogum
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Daybreak.Services.Configuration
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
this.logger.LogWarning($"No configuration detected. Loading default configuration. Details: {e}");
|
||||
this.logger.LogWarning(e, $"Failed to load configuration. Falling back to default configuration");
|
||||
this.applicationConfiguration = new ApplicationConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Extensions;
|
||||
using System.Http;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.IconRetrieve
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace Daybreak.Services.ViewManagement
|
||||
private void ShowViewInner(Type viewType, object dataContext)
|
||||
{
|
||||
var scopedManager = this.serviceManager.CreateScope();
|
||||
scopedManager.As<IServiceManager>().RegisterScoped<ScopeMetadata, ScopeMetadata>((sp) => new ScopeMetadata(new CorrelationVector()));
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var view = scopedManager.GetService(viewType).As<UserControl>();
|
||||
|
||||
@@ -3,7 +3,6 @@ using Daybreak.Exceptions;
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Models.Github;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Utils;
|
||||
using Daybreak.Views;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Win32;
|
||||
@@ -12,7 +11,6 @@ using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Http;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
@@ -26,35 +24,15 @@ namespace Daybreak.Services.Updater
|
||||
{
|
||||
public sealed class ApplicationUpdater : IApplicationUpdater
|
||||
{
|
||||
private const string LaunchActionName = "Launch_Daybreak";
|
||||
private const string ExecutionPolicyKey = "ExecutionPolicy";
|
||||
private const string InstallerFileName = "Daybreak.Installer.exe";
|
||||
private const string UpdatedKey = "Updating";
|
||||
private const string RegistryKey = "Daybreak";
|
||||
private const string ExtractAndRunPs1 = "ExtractAndRun.ps1";
|
||||
private const string TempFile = "tempfile.zip";
|
||||
private const string VersionTag = "{VERSION}";
|
||||
private const string InputFileTag = "{INPUTFILE}";
|
||||
private const string OutputPathTag = "{OUTPUTPATH}";
|
||||
private const string ExecutionPolicyTag = "{EXECUTIONPOLICY}";
|
||||
private const string ProcessIdTag = "{PROCESSID}";
|
||||
private const string ExecutableNameTag = "{EXECUTABLE}";
|
||||
private const string WorkingDirectoryTag = "{WORKINGDIRECTORY}";
|
||||
private const string RefTagPrefix = "/refs/tags";
|
||||
private const string VersionListUrl = "https://api.github.com/repos/AlexMacocian/Daybreak/git/refs/tags";
|
||||
private const string Url = "https://github.com/AlexMacocian/Daybreak/releases/latest";
|
||||
private const string DownloadUrl = $"https://github.com/AlexMacocian/Daybreak/releases/download/{VersionTag}/Daybreak{VersionTag}.zip";
|
||||
private const string GetExecutionPolicyCommand = "Get-ExecutionPolicy -Scope CurrentUser";
|
||||
private const string SetExecutionPolicyCommand = $"Set-ExecutionPolicy {ExecutionPolicyTag} -Scope CurrentUser -Force";
|
||||
private const string WaitCommand = $"Wait-Process -Id {ProcessIdTag}";
|
||||
private const string ExtractCommandTemplate = $"Expand-Archive -Path '{InputFileTag}' -DestinationPath '{OutputPathTag}' -Force";
|
||||
private const string PrepareScheduledAction = $"$action = New-ScheduledTaskAction -Execute {ExecutableNameTag} -WorkingDirectory {WorkingDirectoryTag}";
|
||||
private const string PrepareTriggerForAction = $"$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date)";
|
||||
private const string RegisterScheduledAction = $"Register-ScheduledTask -Action $action -Trigger $trigger -TaskName {LaunchActionName} | Out-Null";
|
||||
private const string LaunchScheduledAction = $"Start-ScheduledTask -TaskName {LaunchActionName}";
|
||||
private const string SleepOneSecond = $"Start-Sleep -s 1";
|
||||
private const string UnregisterScheduledAction = $"Unregister-ScheduledTask -TaskName {LaunchActionName} -Confirm:$false";
|
||||
private const string RemoveTempFile = $"Remove-item {TempFile}";
|
||||
private const string RemovePs1 = $"Remove-item {ExtractAndRunPs1}";
|
||||
|
||||
private readonly CancellationTokenSource updateCancellationTokenSource = new();
|
||||
private readonly ILogger<ApplicationUpdater> logger;
|
||||
@@ -191,23 +169,7 @@ namespace Daybreak.Services.Updater
|
||||
|
||||
public void FinalizeUpdate()
|
||||
{
|
||||
var maybeExecutionPolicy = this.RetrieveExecutionPolicy();
|
||||
maybeExecutionPolicy.DoAny(
|
||||
onNone: () =>
|
||||
{
|
||||
throw new InvalidOperationException("Failed to retrieve execution policy");
|
||||
});
|
||||
|
||||
var executionPolicy = maybeExecutionPolicy.ExtractValue();
|
||||
if (executionPolicy is not ExecutionPolicies.Bypass ||
|
||||
executionPolicy is not ExecutionPolicies.Unrestricted)
|
||||
{
|
||||
this.logger.LogInformation($"Execution policy is set to {executionPolicy}. Setting to {ExecutionPolicies.Bypass}");
|
||||
}
|
||||
|
||||
SaveExecutionPolicyValueToRegistry(executionPolicy);
|
||||
MarkUpdateInRegistry();
|
||||
this.SetExecutionPolicy(ExecutionPolicies.Bypass);
|
||||
this.LaunchExtractor();
|
||||
}
|
||||
|
||||
@@ -216,16 +178,6 @@ namespace Daybreak.Services.Updater
|
||||
if (UpdateMarkedInRegistry())
|
||||
{
|
||||
UnmarkUpdateInRegistry();
|
||||
var maybeExecutionPolicy = LoadExecutionPolicyValueFromRegistry();
|
||||
maybeExecutionPolicy.Do(
|
||||
onSome: policy =>
|
||||
{
|
||||
SetExecutionPolicy(policy);
|
||||
},
|
||||
onNone: () =>
|
||||
{
|
||||
throw new InvalidOperationException("Found update marked in registry but no execution policy");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,92 +197,19 @@ namespace Daybreak.Services.Updater
|
||||
return Optional.None<string>();
|
||||
}
|
||||
|
||||
private Optional<ExecutionPolicies> RetrieveExecutionPolicy()
|
||||
{
|
||||
var process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "powershell",
|
||||
Arguments = GetExecutionPolicyCommand,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
this.logger.LogInformation("Checking current execution policy");
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
if (!Enum.TryParse(typeof(ExecutionPolicies), output, out var executionPolicy))
|
||||
{
|
||||
var error = process.StandardError.ReadToEnd();
|
||||
this.logger.LogError($"Failed to retrieve current user execution policy. Stdout: {output}. Stderr: {error}");
|
||||
return Optional.None<ExecutionPolicies>();
|
||||
}
|
||||
|
||||
return executionPolicy.Cast<ExecutionPolicies>();
|
||||
}
|
||||
|
||||
private void SetExecutionPolicy(ExecutionPolicies executionPolicy)
|
||||
{
|
||||
var process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "powershell",
|
||||
Arguments = SetExecutionPolicyCommand.Replace(ExecutionPolicyTag, executionPolicy.ToString()),
|
||||
UseShellExecute = false,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
this.logger.LogInformation($"Setting execution policy to {executionPolicy}");
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
if (!string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
var error = process.StandardError.ReadToEnd();
|
||||
throw new InvalidOperationException($"Failed to set execution policy to {executionPolicy}. Stdout: {output}. Stderr: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchExtractor()
|
||||
{
|
||||
File.WriteAllLines(ExtractAndRunPs1, new List<string>()
|
||||
{
|
||||
WaitCommand.Replace(ProcessIdTag, Environment.ProcessId.ToString()),
|
||||
ExtractCommandTemplate
|
||||
.Replace(InputFileTag, Path.GetFullPath(TempFile))
|
||||
.Replace(OutputPathTag, Directory.GetCurrentDirectory()),
|
||||
RemoveTempFile,
|
||||
PrepareScheduledAction
|
||||
.Replace(ExecutableNameTag, Process.GetCurrentProcess()?.MainModule?.FileName)
|
||||
.Replace(WorkingDirectoryTag, Directory.GetCurrentDirectory()),
|
||||
PrepareTriggerForAction,
|
||||
RegisterScheduledAction,
|
||||
LaunchScheduledAction,
|
||||
SleepOneSecond,
|
||||
UnregisterScheduledAction,
|
||||
RemovePs1,
|
||||
});
|
||||
var process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "powershell.exe",
|
||||
Arguments = $@"{Directory.GetCurrentDirectory()}\{ExtractAndRunPs1}",
|
||||
UseShellExecute = true,
|
||||
WindowStyle = ProcessWindowStyle.Maximized,
|
||||
WorkingDirectory = Directory.GetCurrentDirectory(),
|
||||
Verb = "runas"
|
||||
},
|
||||
FileName = InstallerFileName
|
||||
}
|
||||
};
|
||||
this.logger.LogInformation("Created extractor script. Attempting to launch powershell");
|
||||
this.logger.LogInformation("Launching installer");
|
||||
if (process.Start() is false)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to create and start powershell script");
|
||||
throw new InvalidOperationException("Failed to launch installer");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,40 +247,6 @@ namespace Daybreak.Services.Updater
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void SaveExecutionPolicyValueToRegistry(ExecutionPolicies executionPolicy)
|
||||
{
|
||||
var homeRegistryKey = GetOrCreateHomeKey();
|
||||
homeRegistryKey.SetValue(ExecutionPolicyKey, executionPolicy.ToString());
|
||||
homeRegistryKey.Close();
|
||||
}
|
||||
|
||||
private static Optional<ExecutionPolicies> LoadExecutionPolicyValueFromRegistry()
|
||||
{
|
||||
var homeRegistryKey = GetOrCreateHomeKey();
|
||||
var executionPolicy = homeRegistryKey.GetValue(ExecutionPolicyKey);
|
||||
homeRegistryKey.Close();
|
||||
|
||||
if (executionPolicy is null)
|
||||
{
|
||||
return Optional.None<ExecutionPolicies>();
|
||||
}
|
||||
else if (executionPolicy is string executionPolicyString)
|
||||
{
|
||||
if (Enum.TryParse<ExecutionPolicies>(executionPolicyString, out var executionPolicyValue))
|
||||
{
|
||||
return executionPolicyValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Found execution policy with value {executionPolicy}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Found execution policy of type {executionPolicy.GetType()}.");
|
||||
}
|
||||
}
|
||||
|
||||
private static RegistryKey GetOrCreateHomeKey()
|
||||
{
|
||||
var homeRegistryKey = Registry.CurrentUser.OpenSubKey("Software", true).OpenSubKey(RegistryKey, true);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Daybreak
|
||||
}
|
||||
}
|
||||
private static int Iterations { get; } = 10000;
|
||||
private static RNGCryptoServiceProvider Rng { get; } = new RNGCryptoServiceProvider();
|
||||
private static RandomNumberGenerator Rng { get; } = RandomNumberGenerator.Create();
|
||||
|
||||
public static int BlockSize { get => Aes.BlockSize; }
|
||||
|
||||
@@ -31,29 +31,19 @@ namespace Daybreak
|
||||
var saltBytes = Generate128BitsOfRandomEntropy();
|
||||
var ivBytes = Generate128BitsOfRandomEntropy();
|
||||
|
||||
using (var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations))
|
||||
{
|
||||
var keyBytes = password.GetBytes(Aes.KeySize / 8);
|
||||
using (var encryptor = Aes.CreateEncryptor(keyBytes, ivBytes))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
|
||||
{
|
||||
cryptoStream.Write(bytes, 0, bytes.Length);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
|
||||
using (var encryptedMemoryStream = new MemoryStream((int)(saltBytes.Length + ivBytes.Length + memoryStream.Length)))
|
||||
{
|
||||
encryptedMemoryStream.Write(saltBytes, 0, saltBytes.Length);
|
||||
encryptedMemoryStream.Write(ivBytes, 0, ivBytes.Length);
|
||||
encryptedMemoryStream.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
|
||||
return encryptedMemoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations);
|
||||
var keyBytes = password.GetBytes(Aes.KeySize / 8);
|
||||
using var encryptor = Aes.CreateEncryptor(keyBytes, ivBytes);
|
||||
using var memoryStream = new MemoryStream();
|
||||
using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
|
||||
cryptoStream.Write(bytes, 0, bytes.Length);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
|
||||
using var encryptedMemoryStream = new MemoryStream((int)(saltBytes.Length + ivBytes.Length + memoryStream.Length));
|
||||
encryptedMemoryStream.Write(saltBytes, 0, saltBytes.Length);
|
||||
encryptedMemoryStream.Write(ivBytes, 0, ivBytes.Length);
|
||||
encryptedMemoryStream.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
|
||||
return encryptedMemoryStream.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] DecryptBytes(this byte[] bytes, byte[] key)
|
||||
@@ -61,29 +51,20 @@ namespace Daybreak
|
||||
var saltBytes = new byte[Aes.BlockSize / 8];
|
||||
var ivBytes = new byte[Aes.BlockSize / 8];
|
||||
var cipherBytes = new byte[bytes.Length - Aes.BlockSize / 4];
|
||||
using (MemoryStream encryptedStream = new MemoryStream(bytes))
|
||||
{
|
||||
encryptedStream.Read(saltBytes, 0, saltBytes.Length);
|
||||
encryptedStream.Read(ivBytes, 0, ivBytes.Length);
|
||||
encryptedStream.Read(cipherBytes, 0, cipherBytes.Length);
|
||||
}
|
||||
|
||||
using (var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations))
|
||||
{
|
||||
var keyBytes = password.GetBytes(Aes.KeySize / 8);
|
||||
using (var decryptor = Aes.CreateDecryptor(keyBytes, ivBytes))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(cipherBytes))
|
||||
{
|
||||
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
var plainTextBytes = new byte[memoryStream.Length];
|
||||
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
|
||||
return plainTextBytes.Take(decryptedByteCount).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using var encryptedStream = new MemoryStream(bytes);
|
||||
encryptedStream.Read(saltBytes, 0, saltBytes.Length);
|
||||
encryptedStream.Read(ivBytes, 0, ivBytes.Length);
|
||||
encryptedStream.Read(cipherBytes, 0, cipherBytes.Length);
|
||||
|
||||
using var password = new Rfc2898DeriveBytes(key, saltBytes, Iterations);
|
||||
var keyBytes = password.GetBytes(Aes.KeySize / 8);
|
||||
using var decryptor = Aes.CreateDecryptor(keyBytes, ivBytes);
|
||||
using var memoryStream = new MemoryStream(cipherBytes);
|
||||
using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
|
||||
var plainTextBytes = new byte[memoryStream.Length];
|
||||
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
|
||||
return plainTextBytes.Take(decryptedByteCount).ToArray();
|
||||
}
|
||||
|
||||
private static byte[] Generate128BitsOfRandomEntropy()
|
||||
|
||||
@@ -1,20 +1,9 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace Daybreak.Utils
|
||||
{
|
||||
public static class SerializationExtensions
|
||||
{
|
||||
public static string Serialize<T>(this T obj)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(this string serializedObject)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(serializedObject);
|
||||
}
|
||||
|
||||
public static byte[] AsBytes(this string s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(s);
|
||||
|
||||
@@ -36,17 +36,6 @@ namespace Daybreak.Views
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private bool CheckIfAdmin()
|
||||
{
|
||||
if (this.privilegeManager.AdminPrivileges is false)
|
||||
{
|
||||
this.privilegeManager.RequestAdminPrivileges<MainView>("Application needs to be in administrator mode in order to update.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void NoButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.logger.LogInformation("User declined update");
|
||||
@@ -58,11 +47,6 @@ namespace Daybreak.Views
|
||||
private async void YesButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.logger.LogInformation("User accepted update");
|
||||
if (this.CheckIfAdmin() is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var latestVersion = (await this.applicationUpdater.GetVersions()).Last();
|
||||
this.viewManager.ShowView<UpdateView>(latestVersion);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using Version = Daybreak.Models.Versioning.Version;
|
||||
@@ -39,7 +40,7 @@ namespace Daybreak.Views
|
||||
|
||||
private async void LoadVersionList()
|
||||
{
|
||||
this.Versions.ClearAnd().AddRange(await this.applicationUpdater.GetVersions());
|
||||
this.Versions.ClearAnd().AddRange((await this.applicationUpdater.GetVersions()).Reverse());
|
||||
}
|
||||
|
||||
private void CurrentVersion_Clicked(object sender, EventArgs e)
|
||||
|
||||
@@ -5,6 +5,7 @@ Param(
|
||||
|
||||
Write-Output "Deleting pdb file"
|
||||
Remove-item .\Publish\Daybreak.pdb
|
||||
Remove-item .\Publish\Daybreak.Installer.pdb
|
||||
$zipPath = "Publish\daybreakv$version.zip"
|
||||
Write-Output "Compressing binaries to $zipPath"
|
||||
Compress-Archive .\Publish\* $zipPath -Force
|
||||
|
||||
Reference in New Issue
Block a user