vPOD now also impersonates the pod's TeslaLauncher service, so the console's Manage Site works against it unmodified: - LauncherRpcServer: ILauncherService over OFB + framed JSON on TCP 53290, mirroring TeslaLauncherService (concurrent sessions, out-of-band install zip on a second connection, the 99%-not-100 completion convention). Packages extract to %LocalAppData%\vPOD\Games; postinstall.bat is logged but never executed. - PodProvisioning: pod side of SecureConfig (RQST beacon, RPLY decrypt, RSA session-key exchange), display-only — never touches the NIC/registry. The console's Configure flow mints the key exactly as for a real pod; console Reconfigure (ClearStore) drops the key and re-enters beacon mode. - VirtualLauncher: installed-app registry (persisted), simulated launch PIDs, volume, install progress; console Shutdown/Restart power-cycles the pod. - Form gets a Launcher/Site Management column (passcode display, RPC status, install progress, app list, Reprovision); Power Off darkens the launcher side too; new -nomanage flag disables it. vPOD references the shared Tesla.Contract/Tesla.SecureConfig projects (server side of the existing contract only, no new RPCs). Loopback tests drive the real PodManagerConnection and PodConfigurationServer against the new code (VPodLauncherServerTests, VPodProvisioningTests) — suite now 99 green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
84 lines
3.2 KiB
C#
84 lines
3.2 KiB
C#
using System;
|
|
using System.Net;
|
|
using System.Threading;
|
|
using Tesla;
|
|
using VPod;
|
|
using Xunit;
|
|
|
|
namespace TeslaConsole.DiffTests
|
|
{
|
|
/// <summary>
|
|
/// End-to-end loopback exercise of vPOD's pod-side SecureConfig provisioning
|
|
/// against the REAL console-side implementation (Tesla.PodConfigurationServer,
|
|
/// the exact code the console runs behind Manage Site's "Configure" button):
|
|
/// RQST beacon reception, the AES "RPLY" config broadcast, and the OFB+RSA
|
|
/// session-key exchange must all interoperate.
|
|
///
|
|
/// Uses the protocol's fixed ports (UDP 53291/53292, TCP 53292) and real UDP
|
|
/// broadcasts on loopback — do not run while a console or another vPOD is
|
|
/// provisioning on this machine.
|
|
/// </summary>
|
|
public class VPodProvisioningTests
|
|
{
|
|
[Fact]
|
|
public void Console_Provisions_VPod_And_Both_Hold_The_Same_Session_Key()
|
|
{
|
|
byte[] mac = PodProvisioning.MacForHost(7);
|
|
var provisioning = new PodProvisioning(mac);
|
|
|
|
byte[] beaconMac = null;
|
|
string beaconRequestId = null;
|
|
using (var beaconSeen = new ManualResetEventSlim())
|
|
using (var podProvisioned = new ManualResetEventSlim())
|
|
{
|
|
byte[] podKey = null;
|
|
provisioning.ConfigReceived += _ => { };
|
|
provisioning.Provisioned += key =>
|
|
{
|
|
podKey = key;
|
|
podProvisioned.Set();
|
|
};
|
|
|
|
// The console side: listens on UDP 53291 for RQST beacons; the
|
|
// delegate fires on vPOD's first beacon (sent at Start).
|
|
var consoleServer = new PodConfigurationServer(53291, 53292, (m, id) =>
|
|
{
|
|
beaconMac = m;
|
|
beaconRequestId = id;
|
|
beaconSeen.Set();
|
|
});
|
|
|
|
try
|
|
{
|
|
provisioning.Start();
|
|
Assert.True(beaconSeen.Wait(TimeSpan.FromSeconds(15)),
|
|
"console never received vPOD's RQST beacon");
|
|
Assert.Equal(mac, beaconMac);
|
|
Assert.Equal(provisioning.RequestId, beaconRequestId);
|
|
|
|
// The console side of Configure: broadcast the AES-encrypted
|
|
// network config and run the RSA key exchange against the pod.
|
|
byte[] consoleKey = consoleServer.SendEncryptionKey(
|
|
provisioning.Passphrase,
|
|
IPAddress.Loopback,
|
|
IPAddress.Parse("255.255.255.0"),
|
|
IPAddress.Any,
|
|
IPAddress.Any,
|
|
"vpod-test",
|
|
TimeSpan.FromSeconds(30));
|
|
|
|
Assert.True(podProvisioned.Wait(TimeSpan.FromSeconds(15)),
|
|
"vPOD never completed provisioning");
|
|
Assert.NotNull(consoleKey);
|
|
Assert.Equal(32, consoleKey.Length);
|
|
Assert.Equal(consoleKey, podKey);
|
|
}
|
|
finally
|
|
{
|
|
provisioning.Stop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|