Added hashed based checking of updates.

This commit is contained in:
erik 2025-06-22 22:22:10 +02:00
parent e9925096f0
commit 6120966c05
3 changed files with 1709 additions and 20 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace MosswartMassacre
@ -10,20 +11,47 @@ namespace MosswartMassacre
private const string UPDATE_URL = "https://git.snakedesert.se/SawatoMosswartsEnjoyersClub/MosswartMassacre/raw/branch/spawn-detection/MosswartMassacre/bin/Release/MosswartMassacre.dll";
private static bool updateAvailable = false;
private static long remoteFileSize = 0;
private static long localFileSize = 0;
private static string remoteFileHash = string.Empty;
private static string localFileHash = string.Empty;
private static DateTime lastCheckTime = DateTime.MinValue;
public static bool IsUpdateAvailable => updateAvailable;
public static DateTime LastCheckTime => lastCheckTime;
/// <summary>
/// Calculate SHA256 hash of a file
/// </summary>
private static string CalculateFileHash(string filePath)
{
using (var sha256 = SHA256.Create())
{
using (var stream = File.OpenRead(filePath))
{
byte[] hashBytes = sha256.ComputeHash(stream);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
}
}
}
/// <summary>
/// Calculate SHA256 hash of byte array
/// </summary>
private static string CalculateHash(byte[] data)
{
using (var sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(data);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
}
}
public static async Task<bool> CheckForUpdateAsync()
{
try
{
PluginCore.WriteToChat("[Update] Checking for updates...");
// Get local file size
// Get local file hash
string localPath = GetLocalDllPath();
if (!File.Exists(localPath))
{
@ -31,36 +59,40 @@ namespace MosswartMassacre
return false;
}
localFileSize = new FileInfo(localPath).Length;
PluginCore.WriteToChat("[Update] Calculating local file hash...");
localFileHash = CalculateFileHash(localPath);
// Check remote file size
// Download remote file and calculate hash
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(10);
client.Timeout = TimeSpan.FromSeconds(30);
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, UPDATE_URL));
response.EnsureSuccessStatusCode();
PluginCore.WriteToChat("[Update] Downloading remote file for comparison...");
var remoteData = await client.GetByteArrayAsync(UPDATE_URL);
remoteFileSize = response.Content.Headers.ContentLength ?? 0;
if (remoteFileSize == 0)
if (remoteData == null || remoteData.Length == 0)
{
PluginCore.WriteToChat("[Update] Error: Could not determine remote file size");
PluginCore.WriteToChat("[Update] Error: Could not download remote file");
return false;
}
PluginCore.WriteToChat("[Update] Calculating remote file hash...");
remoteFileHash = CalculateHash(remoteData);
}
// Compare sizes
updateAvailable = (remoteFileSize != localFileSize);
// Compare hashes
updateAvailable = !string.Equals(localFileHash, remoteFileHash, StringComparison.OrdinalIgnoreCase);
lastCheckTime = DateTime.Now;
if (updateAvailable)
{
PluginCore.WriteToChat($"[Update] Update available! Local: {localFileSize} bytes, Remote: {remoteFileSize} bytes");
PluginCore.WriteToChat($"[Update] Update available!");
PluginCore.WriteToChat($"[Update] Local hash: {localFileHash}");
PluginCore.WriteToChat($"[Update] Remote hash: {remoteFileHash}");
}
else
{
PluginCore.WriteToChat("[Update] Up to date");
PluginCore.WriteToChat("[Update] Up to date - hashes match");
}
return true;
@ -112,12 +144,15 @@ namespace MosswartMassacre
}
}
// Validate downloaded file
var downloadedSize = new FileInfo(tempPath).Length;
if (downloadedSize != remoteFileSize)
// Validate downloaded file by hash
PluginCore.WriteToChat("[Update] Validating downloaded file...");
var downloadedHash = CalculateFileHash(tempPath);
if (!string.Equals(downloadedHash, remoteFileHash, StringComparison.OrdinalIgnoreCase))
{
File.Delete(tempPath);
PluginCore.WriteToChat($"[Update] Download validation failed. Expected {remoteFileSize} bytes, got {downloadedSize} bytes");
PluginCore.WriteToChat($"[Update] Download validation failed. Hash mismatch!");
PluginCore.WriteToChat($"[Update] Expected: {remoteFileHash}");
PluginCore.WriteToChat($"[Update] Got: {downloadedHash}");
return false;
}