mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-11-04 16:40:21 +00:00
The initial selective strip covered only the Authorization header, but the dashboard also accepts its JWT via the ?token= query parameter and the nz-jwt cookie (jwt.go TokenLookup channels). A dashboard credential arriving through those channels would still reach a NAT backend. Apply the same classify-then-strip rule to all three channels at NAT ingress: values verified as dashboard-issued are removed, foreign values are preserved byte-for-byte. Adds a ServeNAT flow test exercising the live classifier and a wiring test pinning the gate injection in main().
59 lines
2.2 KiB
Go
59 lines
2.2 KiB
Go
//go:build agentcompat
|
|
|
|
package rpc
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/nezhahq/nezha/model"
|
|
"github.com/nezhahq/nezha/pkg/agentcompatcontract"
|
|
serviceRPC "github.com/nezhahq/nezha/service/rpc"
|
|
)
|
|
|
|
type natCapabilityLease struct {
|
|
active bool
|
|
publicationOwned bool
|
|
streamLease *serviceRPC.AgentCompatNATStreamLease
|
|
access serviceRPC.AgentCompatCapabilityAccess
|
|
handle serviceRPC.AgentCompatNATPublishHandle
|
|
}
|
|
|
|
func prepareNATCapability(request *http.Request, natConfig *model.NAT) (natCapabilityLease, error) {
|
|
values := request.Header.Values(agentcompatcontract.IOStreamCapabilityHeader)
|
|
if len(values) == 0 {
|
|
// No capability header: legacy NAT path. Strip dashboard-issued
|
|
// credentials (panel JWT or panel PAT) from the Authorization header,
|
|
// the ?token= query parameter and the nz-jwt cookie so they never
|
|
// become origin credentials; foreign values are ordinary request data.
|
|
stripDashboardCredentials(request)
|
|
return natCapabilityLease{}, nil
|
|
}
|
|
request.Header.Del(agentcompatcontract.IOStreamCapabilityHeader)
|
|
if len(values) != 1 || values[0] == "" {
|
|
// Invalid capability: nothing is forwarded, but dashboard-issued
|
|
// credentials still must not survive into errors or task data.
|
|
stripDashboardCredentials(request)
|
|
return natCapabilityLease{}, errors.New("invalid NAT capability")
|
|
}
|
|
access, handle, err := serviceRPC.NezhaHandlerSingleton.ConsumeAgentCompatNATCapabilityForProfile(values[0], natConfig.ServerID, natConfig.ID)
|
|
// From here the request bytes may reach the agent (active lease) or the
|
|
// request ends in a 503; either way dashboard-issued credentials are
|
|
// stripped from every TokenLookup channel, foreign ones are forwarded
|
|
// untouched.
|
|
stripDashboardCredentials(request)
|
|
if err != nil {
|
|
return natCapabilityLease{}, errors.New("invalid NAT capability")
|
|
}
|
|
return natCapabilityLease{active: true, access: access, handle: handle}, nil
|
|
}
|
|
|
|
func (lease natCapabilityLease) cleanup(handler *serviceRPC.NezhaHandler) {
|
|
if !lease.active {
|
|
return
|
|
}
|
|
_ = handler.CancelAgentCompatIOStreamCapability(lease.access)
|
|
_ = handler.CloseAgentCompatNATStreamLease(lease.streamLease)
|
|
_ = handler.UnregisterAgentCompatIOStreamCapability(lease.access)
|
|
}
|