Radicade Public Code

This commit is contained in:
JogmansonReal
2026-10-16 23:33:13 -07:00
commit 55175acdf6
832 changed files with 363261 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
using System.Text;
using Xunit;
namespace RadicadeServer.Tests;
public class ImageSignatureRequestTests
{
private static byte[] Metadata(params string[] literals)
{
using var stream = new MemoryStream();
using var writer = new BinaryWriter(stream);
writer.Write(0xFAB11BAFu);
writer.Write(27);
writer.Write(24);
writer.Write(literals.Length * 8);
writer.Write(24 + literals.Length * 8);
writer.Write(literals.Sum(s => Encoding.UTF8.GetByteCount(s)));
int index = 0;
foreach (var literal in literals)
{
int size = Encoding.UTF8.GetByteCount(literal);
writer.Write(size);
writer.Write(index);
index += size;
}
foreach (var literal in literals) writer.Write(Encoding.UTF8.GetBytes(literal));
return stream.ToArray();
}
[Theory]
[InlineData(".rec.net")]
[InlineData(".radicade.internal")]
public void ClientMetadataControlsHeaderEvenOnWrongRoute(string tail)
{
var key = ImageSignatureRequest.DetectKeyId(Metadata("https://img.rec.net", tail));
Assert.Equal("KEY:RSA:p1" + tail, key);
var url = NameserverRedirect.Rewrite("https://img.rec.net/photo?width=64&sig=p1", "https://private.example");
url = ImageSignatureRequest.AddKeyId(url, "https://private.example", key);
Assert.Contains("width=64&sig=p1&rcsig=" + Uri.EscapeDataString(key), url);
var header = RadicadeServer.Images.ImageAPI.SignatureFor(key, "bare", RadicadeServer.Images.ImageAPI.StockKeyId);
Assert.StartsWith("key-id=" + key + "; data=", header);
Assert.Equal(url, ImageSignatureRequest.AddKeyId(url, "https://private.example", key));
}
// Rec Room's own metadata does not use the plain v27 header: the four literal-table
// fields are shuffled into other 32-bit slots, so the reader discovers the layout.
// This writes the same shape (the 20230831 build puts table offset at 0x74, table
// size at 0x24, data offset at 0xA0, data size at 0x3C) at 0x100-aligned offsets.
private static byte[] ShuffledMetadata(params string[] literals)
{
// Real metadata files carry tens of thousands of literals; the reader refuses
// tables that are too small to be one, so the fixture is padded past that floor.
var padded = literals.Concat(Enumerable.Range(0, 40).Select(i => $"filler literal {i}")).ToArray();
int tableOffset = 0x100;
int tableSize = padded.Length * 8;
int dataOffset = tableOffset + tableSize;
int dataSize = padded.Sum(s => Encoding.UTF8.GetByteCount(s));
var file = new byte[dataOffset + dataSize];
BitConverter.GetBytes(0x2EBE0u).CopyTo(file, 0);
BitConverter.GetBytes(tableSize).CopyTo(file, 0x24);
BitConverter.GetBytes(dataSize).CopyTo(file, 0x3C);
BitConverter.GetBytes(tableOffset).CopyTo(file, 0x74);
BitConverter.GetBytes(dataOffset).CopyTo(file, 0xA0);
int index = 0;
for (int i = 0; i < padded.Length; i++)
{
int size = Encoding.UTF8.GetByteCount(padded[i]);
BitConverter.GetBytes(size).CopyTo(file, tableOffset + 8 * i);
BitConverter.GetBytes(index).CopyTo(file, tableOffset + 8 * i + 4);
Encoding.UTF8.GetBytes(padded[i]).CopyTo(file, dataOffset + index);
index += size;
}
return file;
}
[Theory]
[InlineData(".rec.net")]
[InlineData(".radicade.internal")]
public void ShuffledHeaderMetadataIsDiscoveredStructurally(string tail)
{
var metadata = ShuffledMetadata("https://img.rec.net", tail, "another literal");
Assert.Equal("KEY:RSA:p1" + tail, ImageSignatureRequest.DetectKeyIdFromGameMetadata(metadata));
Assert.Equal("KEY:RSA:p1" + tail, ImageSignatureRequest.DetectKeyIdFromGameMetadata(metadata));
// A plain v27 file keeps working through the same entry point.
Assert.Equal("KEY:RSA:p1" + tail, ImageSignatureRequest.DetectKeyIdFromGameMetadata(Metadata(tail)));
}
[Fact]
public void ShuffledHeaderAmbiguityAndGarbageStayUndecided()
{
Assert.Null(ImageSignatureRequest.DetectKeyIdFromGameMetadata(
ShuffledMetadata(".rec.net", ".radicade.internal", "x")));
Assert.Null(ImageSignatureRequest.DetectKeyIdFromGameMetadata(
ShuffledMetadata("https://img.rec.net", "no key tail here")));
Assert.Null(ImageSignatureRequest.DetectKeyIdFromGameMetadata(new byte[512]));
var random = new byte[4096];
new Random(7).NextBytes(random);
Assert.Null(ImageSignatureRequest.DetectKeyIdFromGameMetadata(random));
}
[Fact]
public void InvalidOrAmbiguousMetadataDoesNotGuess()
{
Assert.Null(ImageSignatureRequest.DetectKeyId(new byte[2]));
Assert.Null(ImageSignatureRequest.DetectKeyId(Metadata(".rec.net", ".radicade.internal")));
Assert.Null(ImageSignatureRequest.DetectKeyId(Metadata("https://img.rec.net")));
var invalid = Metadata(".rec.net");
Array.Copy(BitConverter.GetBytes(int.MaxValue), 0, invalid, 12, 4);
Assert.Null(ImageSignatureRequest.DetectKeyId(invalid));
}
[Theory]
[InlineData("https://other.example/images/photo")]
[InlineData("https://private.example.evil/images/photo")]
[InlineData("https://private.example/api/photo")]
[InlineData("http://private.example/images/photo")]
public void OnlyConfiguredServerImagesReceiveHint(string url)
=> Assert.Equal(url, ImageSignatureRequest.AddKeyId(url, "https://private.example", "KEY:RSA:p1.rec.net"));
[Fact]
public void PatchedRouteAndServerBasePathKeepParametersAndReplaceStaleHint()
{
var url = ImageSignatureRequest.AddKeyId("https://private.example/base/images/img/photo?rcsig=old&cropSquare=1#f",
"https://private.example/base/", "KEY:RSA:p1.radicade.internal");
Assert.Equal("https://private.example/base/images/img/photo?cropSquare=1&rcsig=KEY%3ARSA%3Ap1.radicade.internal#f", url);
}
}