Authorize body producers by advertised service

This commit is contained in:
Meta Vens 2026-07-13 22:21:47 +01:00
commit 9f4f88e43c
3 changed files with 66 additions and 3 deletions

View file

@ -55,7 +55,7 @@ namespace GameCult.Eve.UnityScene
private CultNetDatabaseSubscriptionClient? _subscriptions;
private EveProviderAdvertisementDocument? _advertisement;
private EveAdvertisedSurface? _advertisedSurface;
private readonly CultMeshBodyPublicationResolver _bodyResolver;
private CultMeshBodyPublicationResolver? _bodyResolver;
public EveUnityCultMeshLiveProviderTransport(
string replicaPath,
@ -286,6 +286,7 @@ namespace GameCult.Eve.UnityScene
private CultMeshBodyPublicationResolver CreateBodyResolver()
{
var producerId = RequireAdvertisedBodyProducerId(_advertisement);
var mappedRoot = Path.GetDirectoryName(_replicaPath) ?? ".";
return new CultMeshBodyPublicationResolver(new CultMeshBodyTransportService(
new ICultMeshBodyTransportAdapter[]
@ -294,7 +295,20 @@ namespace GameCult.Eve.UnityScene
new CultMeshMappedBodyAdapter(mappedRoot),
new CultMeshNetworkBodyAdapter(ReadNetworkBody)
},
(producerId, _) => string.Equals(producerId, _providerId, StringComparison.Ordinal)));
(candidateProducerId, _) => IsAdvertisedBodyProducer(producerId, candidateProducerId)));
}
private static bool IsAdvertisedBodyProducer(string advertisedProducerId, string candidateProducerId) =>
string.Equals(candidateProducerId, advertisedProducerId, StringComparison.Ordinal);
private static string RequireAdvertisedBodyProducerId(EveProviderAdvertisementDocument? advertisement)
{
if (advertisement == null)
throw new InvalidOperationException("The Eve provider advertisement must be resolved before body transport authorization.");
if (string.IsNullOrWhiteSpace(advertisement.ServiceId))
throw new InvalidOperationException(
$"Eve provider '{advertisement.ProviderId}' does not advertise a service identity for body production.");
return advertisement.ServiceId;
}
private byte[] ReadNetworkBody(CultMeshBodyDescriptor descriptor)
@ -362,6 +376,7 @@ namespace GameCult.Eve.UnityScene
var now = DateTimeOffset.UtcNow;
if (!IsPublicationLive(publication, now))
return;
_bodyResolver ??= CreateBodyResolver();
var lease = _bodyResolver.ResolveReadOnly(publication, new CultMeshBodyValidationRequest
{
BodyId = handle.BodyId,

View file

@ -89,6 +89,39 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(resolved, Is.EqualTo(bytes));
}
[Test]
public void LiveTransportAuthorizesBodiesWithAdvertisedServiceIdentity()
{
var advertisement = ProviderAdvertisement("aetheria", "aetheria.daemon");
var method = typeof(EveUnityCultMeshLiveProviderTransport)
.GetMethod("RequireAdvertisedBodyProducerId", BindingFlags.NonPublic | BindingFlags.Static)!;
var producerId = (string)method.Invoke(null, new object?[] { advertisement })!;
Assert.That(producerId, Is.EqualTo("aetheria.daemon"));
Assert.That(producerId, Is.Not.EqualTo(advertisement.ProviderId));
var authorizes = typeof(EveUnityCultMeshLiveProviderTransport)
.GetMethod("IsAdvertisedBodyProducer", BindingFlags.NonPublic | BindingFlags.Static)!;
Assert.That(authorizes.Invoke(null, new object[] { producerId, "aetheria.daemon" }), Is.True);
Assert.That(authorizes.Invoke(null, new object[] { producerId, "aetheria" }), Is.False);
Assert.That(authorizes.Invoke(null, new object[] { producerId, "impostor" }), Is.False);
}
[Test]
public void LiveTransportRejectsAdvertisementWithoutBodyProducerIdentity()
{
var advertisement = ProviderAdvertisement("aetheria", "");
var method = typeof(EveUnityCultMeshLiveProviderTransport)
.GetMethod("RequireAdvertisedBodyProducerId", BindingFlags.NonPublic | BindingFlags.Static)!;
var error = Assert.Throws<TargetInvocationException>(() =>
method.Invoke(null, new object?[] { advertisement }));
Assert.That(error!.InnerException, Is.TypeOf<InvalidOperationException>());
StringAssert.Contains("does not advertise a service identity", error.InnerException!.Message);
}
[Test]
public void EntitySoaViewReadsGenericSemanticColumnsFromInjectedLease()
{
@ -2009,6 +2042,21 @@ namespace GameCult.Eve.UnityScene.Tests
}
};
private static EveProviderAdvertisementDocument ProviderAdvertisement(string providerId, string serviceId) =>
new EveProviderAdvertisementDocument(
providerId,
serviceId,
"test-verse",
"Test Provider",
"test",
"cultmesh://test/provider",
DateTimeOffset.UtcNow.ToString("O"),
new EveProviderFreshness("fresh", DateTimeOffset.UtcNow.ToString("O"), 5000),
Array.Empty<string>(),
Array.Empty<EveProviderWitness>(),
Array.Empty<EveAdvertisedSurface>(),
Array.Empty<EveAdvertisedCommand>());
private static CultMeshBodyPublicationDocument BodyPublication(
EveEntitySoaViewDocument view,
long sequence)

View file

@ -1,7 +1,7 @@
{
"name": "org.gamecult.eve.unity-scene",
"displayName": "Eve Unity Scene Lowering",
"version": "0.3.2",
"version": "0.3.3",
"unity": "2021.3",
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
"dependencies": {