mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-28 19:23:47 +02:00
Add hash check to updater
This commit is contained in:
14
AppApi.cs
14
AppApi.cs
@@ -428,20 +428,6 @@ namespace VRCX
|
|||||||
broadcastSocket.SendTo(byteBuffer, endPoint);
|
broadcastSocket.SendTo(byteBuffer, endPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Downloads the VRCX update executable from the specified URL and saves it to the AppData directory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url">The URL of the VRCX update to download.</param>
|
|
||||||
public void DownloadVRCXUpdate(string url)
|
|
||||||
{
|
|
||||||
var Location = Path.Combine(Program.AppDataDirectory, "update.exe");
|
|
||||||
using (var client = new WebClient())
|
|
||||||
{
|
|
||||||
client.Headers.Add("user-agent", Program.Version);
|
|
||||||
client.DownloadFile(new Uri(url), Location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restarts the VRCX application for an update by launching a new process with the "/Upgrade" argument and exiting the current process.
|
/// Restarts the VRCX application for an update by launching a new process with the "/Upgrade" argument and exiting the current process.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace VRCX
|
|||||||
|
|
||||||
public static string DownloadTempLocation;
|
public static string DownloadTempLocation;
|
||||||
public static string DownloadDestinationLocation;
|
public static string DownloadDestinationLocation;
|
||||||
|
public static string DownloadHashLocation;
|
||||||
public static int DownloadProgress;
|
public static int DownloadProgress;
|
||||||
public static int DownloadSize;
|
public static int DownloadSize;
|
||||||
public static bool DownloadCanceled;
|
public static bool DownloadCanceled;
|
||||||
@@ -104,18 +105,25 @@ namespace VRCX
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DownloadFile(string url, int size)
|
// old asset bundle cacher downloader method reused for updating, it's not pretty
|
||||||
|
public void DownloadFile(string fileUrl, string hashUrl, int size)
|
||||||
{
|
{
|
||||||
|
client = new WebClient();
|
||||||
|
client.Headers.Add("user-agent", Program.Version);
|
||||||
DownloadProgress = 0;
|
DownloadProgress = 0;
|
||||||
DownloadSize = size;
|
DownloadSize = size;
|
||||||
DownloadCanceled = false;
|
DownloadCanceled = false;
|
||||||
DownloadTempLocation = Path.Combine(Program.AppDataDirectory, "tempDownload.exe");
|
DownloadTempLocation = Path.Combine(Program.AppDataDirectory, "tempDownload.exe");
|
||||||
DownloadDestinationLocation = Path.Combine(Program.AppDataDirectory, "update.exe");
|
DownloadDestinationLocation = Path.Combine(Program.AppDataDirectory, "update.exe");
|
||||||
client = new WebClient();
|
DownloadHashLocation = Path.Combine(Program.AppDataDirectory, "sha256sum.txt");
|
||||||
client.Headers.Add("user-agent", Program.Version);
|
if (File.Exists(DownloadHashLocation))
|
||||||
|
File.Delete(DownloadHashLocation);
|
||||||
|
if (!string.IsNullOrEmpty(hashUrl))
|
||||||
|
client.DownloadFile(new Uri(hashUrl), DownloadHashLocation);
|
||||||
|
|
||||||
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
|
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
|
||||||
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompletedCallback);
|
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompletedCallback);
|
||||||
client.DownloadFileAsync(new System.Uri(url), DownloadTempLocation);
|
client.DownloadFileAsync(new Uri(fileUrl), DownloadTempLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelDownload()
|
public void CancelDownload()
|
||||||
@@ -163,6 +171,27 @@ namespace VRCX
|
|||||||
DownloadProgress = -15;
|
DownloadProgress = -15;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (File.Exists(DownloadHashLocation))
|
||||||
|
{
|
||||||
|
logger.Info("Updater: Checking hash");
|
||||||
|
var lines = File.ReadAllLines(DownloadHashLocation);
|
||||||
|
var hash = lines.Length > 0 ? lines[0].Split(' ') : new[] { "" };
|
||||||
|
using (var sha256 = SHA256.Create())
|
||||||
|
using (var stream = File.OpenRead(DownloadTempLocation))
|
||||||
|
{
|
||||||
|
var hashBytes = sha256.ComputeHash(stream);
|
||||||
|
var hashString = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
|
||||||
|
if (hashString != hash[0])
|
||||||
|
{
|
||||||
|
logger.Error($"Updater: Hash check failed file:{hashString} remote:{hash[0]}");
|
||||||
|
// can't delete file yet because it's in use
|
||||||
|
DownloadProgress = -14;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Info("Updater: Hash check passed");
|
||||||
|
}
|
||||||
|
|
||||||
if (File.Exists(DownloadDestinationLocation))
|
if (File.Exists(DownloadDestinationLocation))
|
||||||
File.Delete(DownloadDestinationLocation);
|
File.Delete(DownloadDestinationLocation);
|
||||||
File.Move(DownloadTempLocation, DownloadDestinationLocation);
|
File.Move(DownloadTempLocation, DownloadDestinationLocation);
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ namespace VRCX
|
|||||||
{
|
{
|
||||||
if (Process.GetProcessesByName("VRCX_Setup").Length > 0)
|
if (Process.GetProcessesByName("VRCX_Setup").Length > 0)
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
|
var setupHash = Path.Combine(Program.AppDataDirectory, "sha256sum.txt");
|
||||||
|
if (File.Exists(setupHash))
|
||||||
|
File.Delete(setupHash);
|
||||||
|
var tempDownload = Path.Combine(Program.AppDataDirectory, "tempDownload.exe");
|
||||||
|
if (File.Exists(tempDownload))
|
||||||
|
File.Delete(tempDownload);
|
||||||
if (File.Exists(VRCX_Setup_Executable))
|
if (File.Exists(VRCX_Setup_Executable))
|
||||||
File.Delete(VRCX_Setup_Executable);
|
File.Delete(VRCX_Setup_Executable);
|
||||||
if (File.Exists(Update_Executable))
|
if (File.Exists(Update_Executable))
|
||||||
|
|||||||
@@ -21952,9 +21952,10 @@ speechSynthesis.getVoices();
|
|||||||
this.downloadQueue.delete(ref.id);
|
this.downloadQueue.delete(ref.id);
|
||||||
this.downloadQueueTable.data = Array.from(this.downloadQueue.values());
|
this.downloadQueueTable.data = Array.from(this.downloadQueue.values());
|
||||||
|
|
||||||
var url = this.downloadCurrent.updateZipUrl;
|
var fileUrl = this.downloadCurrent.updateSetupUrl;
|
||||||
|
var hashUrl = this.downloadCurrent.updateHashUrl;
|
||||||
var size = this.downloadCurrent.size;
|
var size = this.downloadCurrent.size;
|
||||||
await AssetBundleCacher.DownloadFile(url, size);
|
await AssetBundleCacher.DownloadFile(fileUrl, hashUrl, size);
|
||||||
this.downloadFileProgress();
|
this.downloadFileProgress();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -21993,9 +21994,16 @@ speechSynthesis.getVoices();
|
|||||||
});
|
});
|
||||||
this.downloadFileComplete('Canceled');
|
this.downloadFileComplete('Canceled');
|
||||||
return;
|
return;
|
||||||
|
case -14:
|
||||||
|
this.$message({
|
||||||
|
message: 'Download failed, hash mismatch',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
this.downloadFileComplete('Failed');
|
||||||
|
return;
|
||||||
case -15:
|
case -15:
|
||||||
this.$message({
|
this.$message({
|
||||||
message: 'Download failed',
|
message: 'Download failed, size mismatch',
|
||||||
type: 'error'
|
type: 'error'
|
||||||
});
|
});
|
||||||
this.downloadFileComplete('Failed');
|
this.downloadFileComplete('Failed');
|
||||||
@@ -22803,7 +22811,8 @@ speechSynthesis.getVoices();
|
|||||||
};
|
};
|
||||||
|
|
||||||
$app.methods.downloadVRCXUpdate = function (
|
$app.methods.downloadVRCXUpdate = function (
|
||||||
updateZipUrl,
|
updateSetupUrl,
|
||||||
|
updateHashUrl,
|
||||||
size,
|
size,
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
@@ -22816,7 +22825,8 @@ speechSynthesis.getVoices();
|
|||||||
this.downloadQueue.set('VRCXUpdate', {
|
this.downloadQueue.set('VRCXUpdate', {
|
||||||
ref,
|
ref,
|
||||||
type,
|
type,
|
||||||
updateZipUrl,
|
updateSetupUrl,
|
||||||
|
updateHashUrl,
|
||||||
size,
|
size,
|
||||||
autoInstall
|
autoInstall
|
||||||
});
|
});
|
||||||
@@ -22829,17 +22839,27 @@ speechSynthesis.getVoices();
|
|||||||
$app.methods.installVRCXUpdate = function () {
|
$app.methods.installVRCXUpdate = function () {
|
||||||
for (var release of this.VRCXUpdateDialog.releases) {
|
for (var release of this.VRCXUpdateDialog.releases) {
|
||||||
if (release.name === this.VRCXUpdateDialog.release) {
|
if (release.name === this.VRCXUpdateDialog.release) {
|
||||||
|
var downloadUrl = '';
|
||||||
|
var hashUrl = '';
|
||||||
|
var size = 0;
|
||||||
for (var asset of release.assets) {
|
for (var asset of release.assets) {
|
||||||
|
if (asset.state !== 'uploaded') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
(asset.content_type === 'application/x-msdownload' ||
|
asset.content_type === 'application/x-msdownload' ||
|
||||||
asset.content_type ===
|
asset.content_type === 'application/x-msdos-program'
|
||||||
'application/x-msdos-program') &&
|
|
||||||
asset.state === 'uploaded'
|
|
||||||
) {
|
) {
|
||||||
var downloadUrl = asset.browser_download_url;
|
downloadUrl = asset.browser_download_url;
|
||||||
var size = asset.size;
|
size = asset.size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
asset.name === 'SHA256SUMS.txt' &&
|
||||||
|
asset.content_type === 'text/plain'
|
||||||
|
) {
|
||||||
|
hashUrl = asset.browser_download_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!downloadUrl) {
|
if (!downloadUrl) {
|
||||||
return;
|
return;
|
||||||
@@ -22849,6 +22869,7 @@ speechSynthesis.getVoices();
|
|||||||
var autoInstall = false;
|
var autoInstall = false;
|
||||||
this.downloadVRCXUpdate(
|
this.downloadVRCXUpdate(
|
||||||
downloadUrl,
|
downloadUrl,
|
||||||
|
hashUrl,
|
||||||
size,
|
size,
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
@@ -22960,17 +22981,27 @@ speechSynthesis.getVoices();
|
|||||||
// update already downloaded
|
// update already downloaded
|
||||||
this.VRCXUpdateDialog.updatePendingIsLatest = true;
|
this.VRCXUpdateDialog.updatePendingIsLatest = true;
|
||||||
} else if (name > this.appVersion) {
|
} else if (name > this.appVersion) {
|
||||||
|
var downloadUrl = '';
|
||||||
|
var hashUrl = '';
|
||||||
|
var size = 0;
|
||||||
for (var asset of json.assets) {
|
for (var asset of json.assets) {
|
||||||
|
if (asset.state !== 'uploaded') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
(asset.content_type === 'application/x-msdownload' ||
|
asset.content_type === 'application/x-msdownload' ||
|
||||||
asset.content_type ===
|
asset.content_type === 'application/x-msdos-program'
|
||||||
'application/x-msdos-program') &&
|
|
||||||
asset.state === 'uploaded'
|
|
||||||
) {
|
) {
|
||||||
var downloadUrl = asset.browser_download_url;
|
downloadUrl = asset.browser_download_url;
|
||||||
var size = asset.size;
|
size = asset.size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
asset.name === 'SHA256SUMS.txt' &&
|
||||||
|
asset.content_type === 'text/plain'
|
||||||
|
) {
|
||||||
|
hashUrl = asset.browser_download_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!downloadUrl) {
|
if (!downloadUrl) {
|
||||||
return;
|
return;
|
||||||
@@ -22986,6 +23017,7 @@ speechSynthesis.getVoices();
|
|||||||
var autoInstall = false;
|
var autoInstall = false;
|
||||||
this.downloadVRCXUpdate(
|
this.downloadVRCXUpdate(
|
||||||
downloadUrl,
|
downloadUrl,
|
||||||
|
hashUrl,
|
||||||
size,
|
size,
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
@@ -22995,6 +23027,7 @@ speechSynthesis.getVoices();
|
|||||||
var autoInstall = true;
|
var autoInstall = true;
|
||||||
this.downloadVRCXUpdate(
|
this.downloadVRCXUpdate(
|
||||||
downloadUrl,
|
downloadUrl,
|
||||||
|
hashUrl,
|
||||||
size,
|
size,
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
|
|||||||
Reference in New Issue
Block a user