fix(gateway): close Phase 3C audit gaps

This commit is contained in:
sechmachine
2026-07-30 01:46:00 +07:00
parent 040ca73ce9
commit d3852d15f3
23 changed files with 1619 additions and 219 deletions
+44 -9
View File
@@ -19,13 +19,14 @@ import (
)
const (
defaultHelloLimit = 16 * 1024
defaultControlLimit = 128 * 1024
clientControlBacklog = 64
applicationError = quic.ApplicationErrorCode(0x100)
controlFlowID = "control.ack.v1"
inputFlowID = "input.sequenced.v1"
clipboardFlowID = "clipboard.text.v1"
defaultHelloLimit = 16 * 1024
defaultControlLimit = 128 * 1024
clientControlBacklog = 64
applicationError = quic.ApplicationErrorCode(0x100)
terminalFeedbackDrain = 100 * time.Millisecond
controlFlowID = "control.ack.v1"
inputFlowID = "input.sequenced.v1"
clipboardFlowID = "clipboard.text.v1"
)
var (
@@ -324,12 +325,26 @@ func (s *Server) validateProviderWork(work protocol.ProviderSessionWork, authori
}
if work.SessionID != authority.SessionID || work.GatewayID != authority.GatewayID ||
work.ReconnectSequence != authority.ReconnectSequence || work.ExpiresAt != authority.ExpiresAt ||
work.ProviderProfile != authority.ProviderProfile {
work.ProviderProfile != authority.ProviderProfile || !apolloPolicyMatchesCapabilities(work.StreamPolicy, authority.Capabilities) {
return ErrAdmissionRejected
}
return nil
}
func apolloPolicyMatchesCapabilities(policy protocol.ProviderStreamPolicy, capabilities protocol.CapabilityProfile) bool {
if validateApolloStreamPolicy(policy) != nil || capabilities.Audio != "encoded" {
return false
}
switch policy.Codec {
case "H264":
return capabilities.ClientDecode == "h264-opus" || capabilities.ClientDecode == defaultClientDecode
case "HEVC":
return capabilities.ClientDecode == "hevc-opus" || capabilities.ClientDecode == defaultClientDecode
default:
return false
}
}
func (s *Server) addSession(session *gatewaySession) {
s.mu.Lock()
s.sessions[session] = struct{}{}
@@ -358,6 +373,7 @@ type gatewaySession struct {
pressed map[string]struct{}
sequence atomic.Uint32
mediaDrops uint64
endReason error
result chan error
}
@@ -389,7 +405,7 @@ func (s *gatewaySession) run() {
case <-timer.C:
s.server.metrics.InputRejected.Add(1)
case <-s.ctx.Done():
case <-s.result:
case s.endReason = <-s.result:
}
s.cancel()
}
@@ -404,6 +420,10 @@ func (s *gatewaySession) providerEventLoop() {
if !ok {
return
}
if event.Kind == ProviderEventDisconnected {
s.result <- ErrProviderDisconnected
return
}
payload, err := EncodeProviderEvent(event)
if err == nil {
err = s.sendControl(s.sequence.Add(1), payload)
@@ -412,6 +432,17 @@ func (s *gatewaySession) providerEventLoop() {
s.result <- err
return
}
if event.Kind == ProviderEventTerminated {
timer := time.NewTimer(terminalFeedbackDrain)
select {
case <-s.ctx.Done():
timer.Stop()
return
case <-timer.C:
}
s.result <- ErrProviderTerminated
return
}
}
}
}
@@ -771,6 +802,10 @@ func (s *gatewaySession) cleanup() {
_ = s.connection.CloseWithError(applicationError, "session closed")
return
}
if errors.Is(s.endReason, ErrProviderDisconnected) {
state.State = ProviderStateDisconnected
state.CleanupPending = false
}
if err := s.server.config.Admission.Release(cleanupCtx, s.authority); err != nil {
s.server.metrics.ProviderErrors.Add(1)
}