You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
2.4 KiB

// Package managementaccess owns the narrow runtime boundary used to make
// staged management-service settings real on the target.
package managementaccess
import (
"context"
"errors"
"fmt"
"strings"
"tera-clone/services/tera-api/internal/domain"
)
const DefaultSocketPath = "/run/tera-accessd/control.sock"
type Controller interface {
Apply(context.Context, domain.ManagementAccessSettings) error
}
type NoopController struct{}
func (NoopController) Apply(context.Context, domain.ManagementAccessSettings) error { return nil }
type UnavailableError struct{ Reason string }
func (e *UnavailableError) Error() string {
reason := strings.TrimSpace(e.Reason)
if reason == "" {
reason = "tera-accessd is unavailable"
}
return reason
}
func IsUnavailable(err error) bool {
var target *UnavailableError
return errors.As(err, &target)
}
func Validate(settings domain.ManagementAccessSettings) error {
if settings.IdleTimeoutMinutes < 1 || settings.IdleTimeoutMinutes > 120 {
return errors.New("idle_timeout_minutes must be between 1 and 120")
}
if settings.SSHEnabled || settings.TelnetEnabled {
return errors.New("management access SSH and Telnet are excluded; use per-channel SSH or Telnet access")
}
if settings.LoginDetectionMinutes < 0 || settings.LoginDetectionMinutes > 1440 {
return errors.New("login_detection_minutes must be between 0 and 1440")
}
if settings.LoginSecurityHitCount < 0 || settings.LoginSecurityHitCount > 100 {
return errors.New("login_security_hit_count must be between 0 and 100")
}
if !settings.HTTPSEnabled && !settings.SerialConsoleEnabled {
return errors.New("management access must keep HTTPS or serial console enabled")
}
ports := []struct {
name string
port int
enabled bool
}{
{"http", settings.HTTPPort, settings.HTTPEnabled},
{"https", settings.HTTPSPort, settings.HTTPSEnabled},
}
active := make(map[int]string)
for _, item := range ports {
if item.port < 1 || item.port > 65535 {
return fmt.Errorf("management access %s port must be between 1 and 65535", item.name)
}
if !item.enabled {
continue
}
if item.port == 8080 {
return fmt.Errorf("management access %s port 8080 is reserved for the recovery-safe web endpoint", item.name)
}
if previous, exists := active[item.port]; exists {
return fmt.Errorf("management access services %s and %s cannot share port %d", previous, item.name, item.port)
}
active[item.port] = item.name
}
return nil
}