mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 17:50:12 +00:00
97 lines
3.9 KiB
Go
97 lines
3.9 KiB
Go
//go:build agentcompat
|
|
|
|
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
)
|
|
|
|
const agentCompatCapabilityTokenAttempts = 32
|
|
|
|
func validAgentCompatRegistration(registration AgentCompatCapabilityRegistration) bool {
|
|
if !registration.ServerAccessAllowed || registration.Owner.PATID == 0 || registration.Owner.UserID == 0 || registration.TargetServerID == 0 {
|
|
return false
|
|
}
|
|
switch registration.Purpose {
|
|
case AgentCompatCapabilityTerminal, AgentCompatCapabilityFileManager:
|
|
return registration.ResourceID == 0
|
|
case AgentCompatCapabilityNAT:
|
|
return registration.ResourceID != 0
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (s *NezhaHandler) RegisterAgentCompatIOStreamCapability(ctx context.Context, registration AgentCompatCapabilityRegistration) (AgentCompatIOStreamCapability, error) {
|
|
if !validAgentCompatRegistration(registration) {
|
|
return AgentCompatIOStreamCapability{}, ErrAgentCompatCapabilityHidden
|
|
}
|
|
if err := ctx.Err(); err != nil {
|
|
return AgentCompatIOStreamCapability{}, err
|
|
}
|
|
s.ioStreamMutex.RLock()
|
|
tokenSource := s.agentCompatCapabilities.tokenSource
|
|
quotaAvailable := s.agentCompatCapabilityQuotaAvailableLocked(registration.Owner.PATID)
|
|
s.ioStreamMutex.RUnlock()
|
|
if !quotaAvailable {
|
|
return AgentCompatIOStreamCapability{}, ErrAgentCompatCapabilityUnavailable
|
|
}
|
|
for range agentCompatCapabilityTokenAttempts {
|
|
if err := ctx.Err(); err != nil {
|
|
return AgentCompatIOStreamCapability{}, err
|
|
}
|
|
// Token generation may block or reenter the registry, so it must never run under ioStreamMutex.
|
|
raw := make([]byte, 32)
|
|
if err := tokenSource(raw); err != nil {
|
|
return AgentCompatIOStreamCapability{}, err
|
|
}
|
|
capability := AgentCompatIOStreamCapability{value: base64.RawURLEncoding.EncodeToString(raw)}
|
|
|
|
if err := ctx.Err(); err != nil {
|
|
return AgentCompatIOStreamCapability{}, err
|
|
}
|
|
s.ioStreamMutex.Lock()
|
|
// Recheck every quota under the insertion lock so concurrent mints cannot oversubscribe any bound.
|
|
if !s.agentCompatCapabilityQuotaAvailableLocked(registration.Owner.PATID) {
|
|
s.ioStreamMutex.Unlock()
|
|
return AgentCompatIOStreamCapability{}, ErrAgentCompatCapabilityUnavailable
|
|
}
|
|
if _, used := s.agentCompatCapabilities.used[capability.value]; used {
|
|
s.ioStreamMutex.Unlock()
|
|
continue
|
|
}
|
|
s.agentCompatCapabilities.used[capability.value] = struct{}{}
|
|
s.agentCompatCapabilities.nextIdentity++
|
|
s.agentCompatCapabilities.activeByPAT[registration.Owner.PATID]++
|
|
s.agentCompatCapabilities.active[capability.value] = &agentCompatCapabilityRegistration{
|
|
registration: registration, phase: agentCompatCapabilityRegistered,
|
|
generation: s.agentCompatCapabilities.nextIdentity, notify: make(chan struct{}),
|
|
}
|
|
s.ioStreamMutex.Unlock()
|
|
return capability, nil
|
|
}
|
|
return AgentCompatIOStreamCapability{}, ErrAgentCompatCapabilityTokenExhausted
|
|
}
|
|
|
|
func (s *NezhaHandler) agentCompatCapabilityQuotaAvailableLocked(patID uint64) bool {
|
|
return s.agentCompatCapabilities.activeByPAT[patID] < agentCompatCapabilityMaxActivePerPAT &&
|
|
len(s.agentCompatCapabilities.active) < agentCompatCapabilityMaxActiveGlobal &&
|
|
len(s.agentCompatCapabilities.used) < agentCompatCapabilityMaxProcessMints
|
|
}
|
|
|
|
func sameAgentCompatOwner(left, right AgentCompatCapabilityOwner) bool {
|
|
return left == right
|
|
}
|
|
|
|
func agentCompatAccessMatches(access AgentCompatCapabilityAccess, registration *agentCompatCapabilityRegistration) bool {
|
|
stored := registration.registration
|
|
return access.ServerAccessAllowed && sameAgentCompatOwner(access.Owner, stored.Owner) &&
|
|
access.Purpose == stored.Purpose && access.TargetServerID == stored.TargetServerID && access.ResourceID == stored.ResourceID
|
|
}
|
|
|
|
func (s *NezhaHandler) agentCompatRegistrationLocked(access AgentCompatCapabilityAccess) (*agentCompatCapabilityRegistration, bool) {
|
|
registration, exists := s.agentCompatCapabilities.active[access.Capability.value]
|
|
return registration, exists && agentCompatAccessMatches(access, registration)
|
|
}
|