package cluster import ( "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/hex" "errors" "strings" "time" ) const joinTokenHashPrefix = "sha256:" func generateJoinToken() (string, error) { var random [32]byte if _, err := rand.Read(random[:]); err != nil { return "", err } return "rap_join_" + base64.RawURLEncoding.EncodeToString(random[:]), nil } func hashJoinToken(token string) (string, error) { trimmed := strings.TrimSpace(token) if trimmed == "" { return "", errors.New("join token is required") } sum := sha256.Sum256([]byte(trimmed)) return joinTokenHashPrefix + hex.EncodeToString(sum[:]), nil } func isPlatformAdminRole(role string) bool { return role == PlatformRoleAdmin || role == PlatformRoleRecoveryAdmin } func isAllowedNodeRole(role string) bool { _, ok := allowedNodeRoles[role] return ok } func defaultJoinTokenExpiry(now time.Time) time.Time { return now.Add(30 * time.Minute) }