-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
MWR
committed
Jun 20, 2021
1 parent
205a997
commit e77b221
Showing
19 changed files
with
1,315 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
using System; | ||
using System.IO; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
using DTInstaller.Utils; | ||
using static DTInstaller.Utils.Logger; | ||
using static DTInstaller.Utils.Constants; | ||
|
||
namespace DTInstaller.Commands | ||
{ | ||
class ScriptReinstaller : ICommand | ||
{ | ||
public static (string name, string purpose, string alias) CommandDetails { get; } = | ||
("Reinstall", "reinstall the script", "r"); | ||
public (string name, string purpose, string alias) CommandDetailsInstance { get; } = CommandDetails; | ||
|
||
public async Task<bool> Execute() | ||
{ | ||
Log(LogVariant.Information, Texts.reinstallingMessage); | ||
|
||
string archiveDirectoryPath = ArchiveDirectoryPathAssembler.AssembleArchiveDirectoryPath(); | ||
if (archiveDirectoryPath == null) return false; | ||
|
||
string mainScreenFilePath = Path.Combine(archiveDirectoryPath, Paths.mainScreenFileWithinArchivePath); | ||
string sourceCodeCoreArchivePath = Path.Combine(archiveDirectoryPath, FileNames.archiveFileName); | ||
string archiveUnpackedDirectoryPath = Path.Combine(archiveDirectoryPath, FileNames.unpackedDirectoryName); | ||
|
||
Log(LogVariant.Information, Texts.scriptFetchingMessage); | ||
JsonScriptData scriptCode = await UpdatesManager.GetScript(); | ||
if (scriptCode == null) return false; | ||
|
||
Log(LogVariant.Information, Texts.injectingProcessMessage); | ||
Log(LogVariant.Warning, Texts.dontReopenClientMessage); | ||
ScriptInjector scriptInjector = new( | ||
targetFilePath: mainScreenFilePath, | ||
archiveFilePath: sourceCodeCoreArchivePath, | ||
archiveOutputDirectoryPath: archiveUnpackedDirectoryPath, | ||
scriptCode: Encoding.UTF8.GetString(Convert.FromBase64String(scriptCode.content)) | ||
); | ||
|
||
bool hasInjected = scriptInjector.Inject(); | ||
if (!hasInjected) return false; | ||
|
||
Log(LogVariant.Success, Texts.reinstallationSuccessMessage); | ||
return true; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using System; | ||
using System.IO; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
using DTInstaller.Utils; | ||
using static DTInstaller.Utils.Logger; | ||
using static DTInstaller.Utils.Methods; | ||
using static DTInstaller.Utils.Constants; | ||
|
||
namespace DTInstaller.Commands | ||
{ | ||
class UpdateInstaller : ICommand | ||
{ | ||
public static (string name, string purpose, string alias) CommandDetails { get; } = | ||
("Install", "install the update, if there's one", "i"); | ||
public (string name, string purpose, string alias) CommandDetailsInstance { get; } = CommandDetails; | ||
|
||
public async Task<bool> Execute() | ||
{ | ||
Log(LogVariant.Information, Texts.installingMessage); | ||
|
||
// We check again for an update because otherwise, the user could proceed to install an update | ||
// when there isn't one to begin with. | ||
var (isNewUpdateAvailable, didError) = await UpdatesManager.CheckForUpdates(); | ||
if (didError) return false; | ||
|
||
if (!isNewUpdateAvailable) | ||
{ | ||
Log(LogVariant.Information, Texts.noUpdatesMessage); | ||
return true; | ||
} | ||
|
||
bool didUpdateLocalScriptData = LocalScriptDataManager | ||
.UpdateLocalScriptData(UpdatesManager.FetchedScriptData); | ||
// While this may not stop the installation of the update itself, when the user wants to reinstall | ||
// the script, they'll actually install an old update, so rather than doing that, just fail. | ||
if (!didUpdateLocalScriptData) return false; | ||
|
||
string archiveDirectoryPath = ArchiveDirectoryPathAssembler.AssembleArchiveDirectoryPath(); | ||
if (archiveDirectoryPath == null) return false; | ||
|
||
string mainScreenFilePath = Path.Combine(archiveDirectoryPath, Paths.mainScreenFileWithinArchivePath); | ||
string sourceCodeCoreArchivePath = Path.Combine(archiveDirectoryPath, FileNames.archiveFileName); | ||
string archiveUnpackedDirectory = Path.Combine(archiveDirectoryPath, FileNames.unpackedDirectoryName); | ||
|
||
Log(LogVariant.Information, Texts.injectingProcessMessage); | ||
Log(LogVariant.Warning, Texts.dontReopenClientMessage); | ||
ScriptInjector scriptInjector = new( | ||
targetFilePath: mainScreenFilePath, | ||
archiveFilePath: sourceCodeCoreArchivePath, | ||
archiveOutputDirectoryPath: archiveUnpackedDirectory, | ||
scriptCode: Encoding.UTF8.GetString(Convert.FromBase64String(UpdatesManager.FetchedScriptData.content)) | ||
); | ||
|
||
bool hasInjected = scriptInjector.Inject(); | ||
if (!hasInjected) return false; | ||
|
||
Log(LogVariant.Success, Texts.installationSuccessMessage); | ||
return true; | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net5.0</TargetFramework> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
<ApplicationIcon>dt-icon.ico</ApplicationIcon> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Reference Include="AsarSharp"> | ||
<HintPath>..\AsarSharp\bin\Release\net5.0\AsarSharp.dll</HintPath> | ||
</Reference> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.31129.286 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTInstaller", "DTInstaller.csproj", "{F13AB7E2-B656-4E47-9E71-DA1FC288874F}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{F13AB7E2-B656-4E47-9E71-DA1FC288874F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{F13AB7E2-B656-4E47-9E71-DA1FC288874F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{F13AB7E2-B656-4E47-9E71-DA1FC288874F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{F13AB7E2-B656-4E47-9E71-DA1FC288874F}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {5F586180-2936-444E-A987-E8CA606A6878} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using System; | ||
using System.IO; | ||
using System.Text.Json; | ||
using DTInstaller.Utils; | ||
using static DTInstaller.Utils.Logger; | ||
using static DTInstaller.Utils.Constants; | ||
|
||
namespace DTInstaller | ||
{ | ||
static class LocalScriptDataManager | ||
{ | ||
/** | ||
* <summary>Gets the script data from the local script data file, instead of the repository.</summary> | ||
* <returns>The script data object.</returns> | ||
*/ | ||
public static JsonScriptData GetLocalScriptData() | ||
{ | ||
FileLoader fileLoader = new(path: Paths.localScriptDataFilePath); | ||
string localScriptData = fileLoader.ReadText(); | ||
|
||
if (localScriptData == null) return null; | ||
|
||
try | ||
{ | ||
return JsonSerializer.Deserialize<JsonScriptData>(localScriptData); | ||
} | ||
catch | ||
{ | ||
Log(LogVariant.Warning, Texts.localScriptDataInvalidMessage); | ||
return null; | ||
} | ||
} | ||
|
||
/** | ||
* <summary>Updates the script data file in case a script change has occured.</summary> | ||
* <param name="scriptData">The script data to update the file with.</param> | ||
* <returns>True if the update has been successful, and false otherwise.</returns> | ||
*/ | ||
public static bool UpdateLocalScriptData(JsonScriptData scriptData) | ||
{ | ||
return new FileLoader(path: Paths.localScriptDataFilePath) | ||
.WriteText(JsonSerializer.Serialize(scriptData)); | ||
} | ||
|
||
/** | ||
* <summary> | ||
* Creates the local script data directory, in which we also create the local script data file. | ||
* </summary> | ||
* <param name="fileContents">The script data object to be written to the local script data file.</param> | ||
* <returns>True if the creation of the directory and file was successful, and false otherwise.</returns> | ||
*/ | ||
public static bool CreateLocalScriptData(JsonScriptData fileContents) | ||
{ | ||
if (!Directory.Exists(Paths.localScriptDataDirPath)) | ||
{ | ||
try | ||
{ | ||
Directory.CreateDirectory(Paths.localScriptDataDirPath); | ||
} | ||
catch (Exception error) | ||
{ | ||
Log( | ||
LogVariant.Error, | ||
$"There's been an error trying to create a directory for " + | ||
$"holding data for this installer: {error.Message}" | ||
); | ||
DebugLog(LogVariant.Error, error.ToString()); | ||
return false; | ||
} | ||
} | ||
|
||
FileLoader fileLoader = new(path: Paths.localScriptDataFilePath); | ||
bool hasWritten = fileLoader.WriteText(JsonSerializer.Serialize(fileContents)); | ||
|
||
return hasWritten; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
using System; | ||
using System.Net.Http; | ||
using System.Text.Json; | ||
using System.Threading.Tasks; | ||
|
||
using static DTInstaller.Utils.Logger; | ||
using static DTInstaller.Utils.Constants; | ||
|
||
namespace DTInstaller.Utils | ||
{ | ||
static class UpdatesManager | ||
{ | ||
private static readonly HttpClient _client = new(); | ||
// We use a nullable bool so we can differentiate between unset and error (null/false). | ||
private static bool? _isNewUpdateAvailable = null; | ||
public static JsonScriptData FetchedScriptData { get; private set; } = null; | ||
|
||
/** | ||
* <summary>Checks for updates by pulling data from the repository.</summary> | ||
* <param name="force"> | ||
* Forces to ping the GitHub servers for a new update, rather than getting the update availability | ||
* from an internal field. In other words, it "invalidates the cache". | ||
* </param> | ||
* <returns>A tuple that holds the update availability, and error presences.</returns> | ||
*/ | ||
public static async Task<(bool isNewUpdateAvailable, bool didError)> CheckForUpdates(bool force = false) | ||
{ | ||
if (_isNewUpdateAvailable != null && !force) | ||
return ((bool)_isNewUpdateAvailable, didError: false); | ||
|
||
FetchedScriptData = await GetRepositoryScript(); | ||
if (FetchedScriptData == null) return (isNewUpdateAvailable: false, didError: true); | ||
|
||
JsonScriptData localScriptData = LocalScriptDataManager.GetLocalScriptData(); | ||
|
||
// If true, it might be that it's the first time they get the installer, | ||
// or they removed the local script directory, or the file inside. | ||
if (localScriptData == null) | ||
{ | ||
DebugLog(LogVariant.Information, | ||
$"({nameof(CheckForUpdates)}) Local data directory is not defined. Creating..."); | ||
|
||
bool didCreateScriptDataPlace = LocalScriptDataManager.CreateLocalScriptData(fileContents: FetchedScriptData); | ||
if (!didCreateScriptDataPlace) | ||
return (isNewUpdateAvailable: true, didError: true); | ||
|
||
// Assuming it's the first time they get the installer, say there's an update. | ||
_isNewUpdateAvailable = true; | ||
|
||
return (isNewUpdateAvailable: true, didError: false); | ||
} | ||
|
||
_isNewUpdateAvailable = localScriptData.sha != FetchedScriptData.sha; | ||
|
||
return ((bool)_isNewUpdateAvailable, didError: false); | ||
} | ||
|
||
/** | ||
* <summary> | ||
* Gets the script from the local script data file. If said file doesn't exist, | ||
* it gets the script data from the repository, and creates a new script data file. | ||
* </summary> | ||
* <returns>The script data object.</returns> | ||
*/ | ||
public static async Task<JsonScriptData> GetScript() | ||
{ | ||
JsonScriptData localScriptData = LocalScriptDataManager.GetLocalScriptData(); | ||
if (localScriptData == null) | ||
{ | ||
DebugLog(LogVariant.Information, $"({nameof(GetScript)}) Local data directory is not defined. Pulling script from repo..."); | ||
FetchedScriptData = await GetRepositoryScript(); | ||
if (FetchedScriptData == null) return null; | ||
|
||
DebugLog(LogVariant.Information, $"({nameof(GetScript)}) Creating local script data place..."); | ||
bool didCreateScriptDataPlace = LocalScriptDataManager.CreateLocalScriptData(fileContents: FetchedScriptData); | ||
if (!didCreateScriptDataPlace) return null; | ||
|
||
return FetchedScriptData; | ||
} | ||
|
||
return localScriptData; | ||
} | ||
|
||
/** | ||
* <summary>Makes a request to the servers where the script is hosted, and gets it.</summary> | ||
* <returns>The script data object.</returns> | ||
*/ | ||
public static async Task<JsonScriptData> GetRepositoryScript() | ||
{ | ||
try | ||
{ | ||
HttpRequestMessage requestMessage = new(HttpMethod.Get, URLs.scriptFileURL); | ||
|
||
// GitHub (the current host) requires an "User-Agent" header. | ||
requestMessage.Headers.Add("User-Agent", Miscellaneous.installerHeaderRequest); | ||
|
||
var response = await _client.SendAsync(requestMessage); | ||
FetchedScriptData = JsonSerializer.Deserialize<JsonScriptData>(await response.Content.ReadAsStringAsync()); | ||
|
||
return FetchedScriptData; | ||
} | ||
catch (Exception error) | ||
{ | ||
Log(LogVariant.Error, $"There's been an error fetching the script data: {error.Message}"); | ||
DebugLog(LogVariant.Error, error.ToString()); | ||
return null; | ||
} | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
PathAssemblers/ArchiveDirectoryPath/ArchiveDirectoryPathAssembler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using DTInstaller.PathAssemblers.ArchiveDirectoryPath; | ||
|
||
using static DTInstaller.Utils.Methods; | ||
using static DTInstaller.Utils.Constants; | ||
|
||
namespace DTInstaller | ||
{ | ||
static class ArchiveDirectoryPathAssembler | ||
{ | ||
/** | ||
* <summary> | ||
* Assembles the path to the directory where the archive file with the source code is located. | ||
* </summary> | ||
* <returns>The path to the archive's directory if found, and null otherwise.</returns> | ||
*/ | ||
public static string AssembleArchiveDirectoryPath() | ||
{ | ||
string clientType = GetClientType(); | ||
return OS switch | ||
{ | ||
OperatingSystems.Windows => WindowsPath.AssembleArchiveDirectoryPath(clientType), | ||
OperatingSystems.Linux => LinuxPath.AssembleArchiveDirectoryPath(clientType), | ||
_ => null, | ||
}; | ||
} | ||
} | ||
} |
Oops, something went wrong.