diff --git a/OpenDreamClient/OpenDreamClient.csproj b/OpenDreamClient/OpenDreamClient.csproj
index 0421e82885..190148bd90 100644
--- a/OpenDreamClient/OpenDreamClient.csproj
+++ b/OpenDreamClient/OpenDreamClient.csproj
@@ -17,6 +17,7 @@
+
diff --git a/OpenDreamClient/Resources/DreamResourceManager.cs b/OpenDreamClient/Resources/DreamResourceManager.cs
index a88576c145..e5a197eb8d 100644
--- a/OpenDreamClient/Resources/DreamResourceManager.cs
+++ b/OpenDreamClient/Resources/DreamResourceManager.cs
@@ -5,6 +5,8 @@
using Robust.Shared.ContentPack;
using Robust.Shared.Network;
using Robust.Shared.Utility;
+using System.Linq;
+using SpaceWizards.Sodium;
namespace OpenDreamClient.Resources;
@@ -69,21 +71,32 @@ private void EnsureCacheDirectory() {
}
private void RxBrowseResource(MsgBrowseResource message) {
- _sawmill.Debug($"Received cache check for {message.Filename}");
+ _sawmill.Debug($"Received cache check for {message.Filename} hash: {BitConverter.ToString(message.DataHash)}");
EnsureCacheDirectory();
- if(_resourceManager.UserData.Exists(GetCacheFilePath(message.Filename))){ //TODO CHECK HASH
+ if(_resourceManager.UserData.Exists(GetCacheFilePath(message.Filename)) && GetFileHash(GetCacheFilePath(message.Filename)).SequenceEqual(message.DataHash)){
_sawmill.Debug($"Cache hit for {message.Filename}");
} else {
if(_activeBrowseRscRequests.Contains(message.Filename)) //we've already requested it, don't need to do it again
return;
- _sawmill.Debug($"Cache miss for {message.Filename}, requesting from server.");
+ if (_resourceManager.UserData.Exists(GetCacheFilePath(message.Filename))) {
+ _sawmill.Debug($"Cache hit for {message.Filename} but hashes did not match (hash: {BitConverter.ToString(GetFileHash(GetCacheFilePath(message.Filename)))}). Re-requesting!");
+ _resourceManager.UserData.Delete(GetCacheFilePath(message.Filename));
+ } else
+ _sawmill.Debug($"Cache miss for {message.Filename}, requesting from server.");
_activeBrowseRscRequests.Add(message.Filename);
_netManager.ServerChannel?.SendMessage(new MsgBrowseResourceRequest(){ Filename = message.Filename});
}
}
+ private byte[] GetFileHash(ResPath path) {
+ var stream = _resourceManager.UserData.OpenRead(path);
+ Span filebytes = new(new byte[stream.Length]);
+ stream.ReadToEnd(filebytes);
+ return CryptoGenericHashBlake2B.Hash(32, filebytes, ReadOnlySpan.Empty);
+ }
+
private void RxBrowseResourceResponse(MsgBrowseResourceResponse message) {
- if(_activeBrowseRscRequests.Contains(message.Filename)) {
+ if (_activeBrowseRscRequests.Contains(message.Filename)) {
_activeBrowseRscRequests.Remove(message.Filename);
EnsureCacheDirectory();
CreateCacheFile(message.Filename, message.Data);
@@ -227,7 +240,7 @@ public bool EnsureCacheFile(string filename, int timeoutSeconds = 5) {
return _resourceManager.UserData.Exists(actualPath);
} else {
- _sawmill.Error("Cache was ensured for a file that does not exist in cache and is not requested. Probably somebody called browse() without browse_rsc() first.");
+ _sawmill.Error($"Cache was ensured for a file ({filename}) that does not exist in cache and is not requested. Probably somebody called browse() without browse_rsc() first.");
return false;
}
}
diff --git a/OpenDreamRuntime/DreamConnection.cs b/OpenDreamRuntime/DreamConnection.cs
index 6e0a446a74..fc17ccc9b3 100644
--- a/OpenDreamRuntime/DreamConnection.cs
+++ b/OpenDreamRuntime/DreamConnection.cs
@@ -9,6 +9,7 @@
using OpenDreamShared.Network.Messages;
using Robust.Shared.Enums;
using Robust.Shared.Player;
+using SpaceWizards.Sodium;
namespace OpenDreamRuntime;
@@ -373,7 +374,7 @@ public void BrowseResource(DreamResource resource, string filename) {
var msg = new MsgBrowseResource() {
Filename = filename,
- DataHash = resource.ResourceData.Length //TODO: make a quick hash that can work clientside too
+ DataHash = CryptoGenericHashBlake2B.Hash(32, resource.ResourceData!, ReadOnlySpan.Empty)
};
_permittedBrowseRscFiles[filename] = resource;
@@ -384,7 +385,7 @@ public void HandleBrowseResourceRequest(string filename) {
if(_permittedBrowseRscFiles.TryGetValue(filename, out var dreamResource)) {
var msg = new MsgBrowseResourceResponse() {
Filename = filename,
- Data = dreamResource.ResourceData! //honestly if this is null, something mega fucked up has happened and we should error hard
+ Data = dreamResource.ResourceData!, //honestly if this is null, something mega fucked up has happened and we should error hard
};
_permittedBrowseRscFiles.Remove(filename);
Session?.Channel.SendMessage(msg);
diff --git a/OpenDreamRuntime/OpenDreamRuntime.csproj b/OpenDreamRuntime/OpenDreamRuntime.csproj
index 9d1bf2678e..9bde5a58e9 100644
--- a/OpenDreamRuntime/OpenDreamRuntime.csproj
+++ b/OpenDreamRuntime/OpenDreamRuntime.csproj
@@ -16,6 +16,7 @@
+
diff --git a/OpenDreamShared/Network/Messages/MsgBrowseResource.cs b/OpenDreamShared/Network/Messages/MsgBrowseResource.cs
index b2ca8e2870..e774b87981 100644
--- a/OpenDreamShared/Network/Messages/MsgBrowseResource.cs
+++ b/OpenDreamShared/Network/Messages/MsgBrowseResource.cs
@@ -8,15 +8,15 @@ public sealed class MsgBrowseResource : NetMessage {
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
public string Filename = string.Empty;
- public int DataHash;
+ public byte[] DataHash = [];
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) {
Filename = buffer.ReadString();
- DataHash = buffer.ReadVariableInt32();
+ DataHash = buffer.ReadBytes(32);
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) {
buffer.Write(Filename);
- buffer.WriteVariableInt32(DataHash);
+ buffer.Write(DataHash);
}
}