Authorize body producers by advertised service
This commit is contained in:
parent
41008f1e46
commit
9f4f88e43c
3 changed files with 66 additions and 3 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
Reference in a new issue