diff --git a/server/internal/grpc/proxystream.go b/server/internal/grpc/proxystream.go new file mode 100644 index 0000000..f3ef058 --- /dev/null +++ b/server/internal/grpc/proxystream.go @@ -0,0 +1,47 @@ +package grpcserver + +import ( + "log" + + "gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/grpc/pb" + "gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/proxy" + "gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/services" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// ProxyStream carries one console TCP connection. The agent opens it after +// dialling its own loopback address, and authenticates with the same agent +// token as the command stream plus the single-use proxy_id it was handed. +func (s *vantageServer) ProxyStream(stream pb.Vantage_ProxyStreamServer) error { + msg, err := stream.Recv() + if err != nil { + return status.Errorf(codes.InvalidArgument, "expected initial open message: %v", err) + } + if msg.Open == nil { + return status.Error(codes.InvalidArgument, "first message must be open") + } + + srv, err := services.ValidateAgentToken(msg.Open.ServerId, msg.Open.AgentToken) + if err != nil { + return status.Error(codes.Unauthenticated, "invalid agent token") + } + + if err := serveProxy(proxy.Default, msg.Open, srv.InstanceID, stream); err != nil { + // The reason is deliberately not returned to the agent: an unknown and a + // foreign proxy_id must be indistinguishable. + log.Printf("proxy %s (server %s): %v", msg.Open.ProxyId, msg.Open.ServerId, err) + return status.Error(codes.PermissionDenied, "proxy session unavailable") + } + return nil +} + +// serveProxy claims the pending session and relays it. Split out from the gRPC +// method so the authorisation matrix is testable without a real stream. +func serveProxy(reg *proxy.Registry, open *pb.ProxyOpen, instanceID string, stream proxy.AgentStream) error { + entry, err := reg.Claim(instanceID, open.ServerId, open.ProxyId) + if err != nil { + return err + } + return entry.Session.Serve(stream) +} diff --git a/server/internal/grpc/server.go b/server/internal/grpc/server.go index 313b2bc..fd11bfa 100644 --- a/server/internal/grpc/server.go +++ b/server/internal/grpc/server.go @@ -223,11 +223,6 @@ func (s *vantageServer) CommandStream(stream pb.Vantage_CommandStreamServer) err } } -// ProxyStream is stubbed here; Task 4 implements the real relay handler. -func (s *vantageServer) ProxyStream(stream pb.Vantage_ProxyStreamServer) error { - return status.Errorf(codes.Unimplemented, "method ProxyStream not implemented") -} - func StartGRPC(port int) error { lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) if err != nil {