github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/opts.go (about)

     1  // Copyright 2012-2024 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package server
    15  
    16  import (
    17  	"context"
    18  	"crypto/tls"
    19  	"crypto/x509"
    20  	"errors"
    21  	"flag"
    22  	"fmt"
    23  	"math"
    24  	"net"
    25  	"net/url"
    26  	"os"
    27  	"path"
    28  	"path/filepath"
    29  	"regexp"
    30  	"runtime"
    31  	"strconv"
    32  	"strings"
    33  	"sync/atomic"
    34  	"time"
    35  
    36  	"github.com/nats-io/jwt/v2"
    37  	"github.com/nats-io/nats-server/v2/conf"
    38  	"github.com/nats-io/nats-server/v2/server/certidp"
    39  	"github.com/nats-io/nats-server/v2/server/certstore"
    40  	"github.com/nats-io/nkeys"
    41  )
    42  
    43  var allowUnknownTopLevelField = int32(0)
    44  
    45  // NoErrOnUnknownFields can be used to change the behavior the processing
    46  // of a configuration file. By default, an error is reported if unknown
    47  // fields are found. If `noError` is set to true, no error will be reported
    48  // if top-level unknown fields are found.
    49  func NoErrOnUnknownFields(noError bool) {
    50  	var val int32
    51  	if noError {
    52  		val = int32(1)
    53  	}
    54  	atomic.StoreInt32(&allowUnknownTopLevelField, val)
    55  }
    56  
    57  // PinnedCertSet is a set of lower case hex-encoded sha256 of DER encoded SubjectPublicKeyInfo
    58  type PinnedCertSet map[string]struct{}
    59  
    60  // ClusterOpts are options for clusters.
    61  // NOTE: This structure is no longer used for monitoring endpoints
    62  // and json tags are deprecated and may be removed in the future.
    63  type ClusterOpts struct {
    64  	Name              string            `json:"-"`
    65  	Host              string            `json:"addr,omitempty"`
    66  	Port              int               `json:"cluster_port,omitempty"`
    67  	Username          string            `json:"-"`
    68  	Password          string            `json:"-"`
    69  	AuthTimeout       float64           `json:"auth_timeout,omitempty"`
    70  	Permissions       *RoutePermissions `json:"-"`
    71  	TLSTimeout        float64           `json:"-"`
    72  	TLSConfig         *tls.Config       `json:"-"`
    73  	TLSMap            bool              `json:"-"`
    74  	TLSCheckKnownURLs bool              `json:"-"`
    75  	TLSPinnedCerts    PinnedCertSet     `json:"-"`
    76  	ListenStr         string            `json:"-"`
    77  	Advertise         string            `json:"-"`
    78  	NoAdvertise       bool              `json:"-"`
    79  	ConnectRetries    int               `json:"-"`
    80  	PoolSize          int               `json:"-"`
    81  	PinnedAccounts    []string          `json:"-"`
    82  	Compression       CompressionOpts   `json:"-"`
    83  	PingInterval      time.Duration     `json:"-"`
    84  	MaxPingsOut       int               `json:"-"`
    85  
    86  	// Not exported (used in tests)
    87  	resolver netResolver
    88  	// Snapshot of configured TLS options.
    89  	tlsConfigOpts *TLSConfigOpts
    90  }
    91  
    92  // CompressionOpts defines the compression mode and optional configuration.
    93  type CompressionOpts struct {
    94  	Mode string
    95  	// If `Mode` is set to CompressionS2Auto, RTTThresholds provides the
    96  	// thresholds at which the compression level will go from
    97  	// CompressionS2Uncompressed to CompressionS2Fast, CompressionS2Better
    98  	// or CompressionS2Best. If a given level is not desired, specify 0
    99  	// for this slot. For instance, the slice []{0, 10ms, 20ms} means that
   100  	// for any RTT up to 10ms included the compression level will be
   101  	// CompressionS2Fast, then from ]10ms..20ms], the level will be selected
   102  	// as CompressionS2Better. Anything above 20ms will result in picking
   103  	// the CompressionS2Best compression level.
   104  	RTTThresholds []time.Duration
   105  }
   106  
   107  // GatewayOpts are options for gateways.
   108  // NOTE: This structure is no longer used for monitoring endpoints
   109  // and json tags are deprecated and may be removed in the future.
   110  type GatewayOpts struct {
   111  	Name              string               `json:"name"`
   112  	Host              string               `json:"addr,omitempty"`
   113  	Port              int                  `json:"port,omitempty"`
   114  	Username          string               `json:"-"`
   115  	Password          string               `json:"-"`
   116  	AuthTimeout       float64              `json:"auth_timeout,omitempty"`
   117  	TLSConfig         *tls.Config          `json:"-"`
   118  	TLSTimeout        float64              `json:"tls_timeout,omitempty"`
   119  	TLSMap            bool                 `json:"-"`
   120  	TLSCheckKnownURLs bool                 `json:"-"`
   121  	TLSPinnedCerts    PinnedCertSet        `json:"-"`
   122  	Advertise         string               `json:"advertise,omitempty"`
   123  	ConnectRetries    int                  `json:"connect_retries,omitempty"`
   124  	Gateways          []*RemoteGatewayOpts `json:"gateways,omitempty"`
   125  	RejectUnknown     bool                 `json:"reject_unknown,omitempty"` // config got renamed to reject_unknown_cluster
   126  
   127  	// Not exported, for tests.
   128  	resolver         netResolver
   129  	sendQSubsBufSize int
   130  
   131  	// Snapshot of configured TLS options.
   132  	tlsConfigOpts *TLSConfigOpts
   133  }
   134  
   135  // RemoteGatewayOpts are options for connecting to a remote gateway
   136  // NOTE: This structure is no longer used for monitoring endpoints
   137  // and json tags are deprecated and may be removed in the future.
   138  type RemoteGatewayOpts struct {
   139  	Name          string      `json:"name"`
   140  	TLSConfig     *tls.Config `json:"-"`
   141  	TLSTimeout    float64     `json:"tls_timeout,omitempty"`
   142  	URLs          []*url.URL  `json:"urls,omitempty"`
   143  	tlsConfigOpts *TLSConfigOpts
   144  }
   145  
   146  // LeafNodeOpts are options for a given server to accept leaf node connections and/or connect to a remote cluster.
   147  type LeafNodeOpts struct {
   148  	Host              string        `json:"addr,omitempty"`
   149  	Port              int           `json:"port,omitempty"`
   150  	Username          string        `json:"-"`
   151  	Password          string        `json:"-"`
   152  	Nkey              string        `json:"-"`
   153  	Account           string        `json:"-"`
   154  	Users             []*User       `json:"-"`
   155  	AuthTimeout       float64       `json:"auth_timeout,omitempty"`
   156  	TLSConfig         *tls.Config   `json:"-"`
   157  	TLSTimeout        float64       `json:"tls_timeout,omitempty"`
   158  	TLSMap            bool          `json:"-"`
   159  	TLSPinnedCerts    PinnedCertSet `json:"-"`
   160  	TLSHandshakeFirst bool          `json:"-"`
   161  	Advertise         string        `json:"-"`
   162  	NoAdvertise       bool          `json:"-"`
   163  	ReconnectInterval time.Duration `json:"-"`
   164  
   165  	// Compression options
   166  	Compression CompressionOpts `json:"-"`
   167  
   168  	// For solicited connections to other clusters/superclusters.
   169  	Remotes []*RemoteLeafOpts `json:"remotes,omitempty"`
   170  
   171  	// This is the minimum version that is accepted for remote connections.
   172  	// Note that since the server version in the CONNECT protocol was added
   173  	// only starting at v2.8.0, any version below that will be rejected
   174  	// (since empty version string in CONNECT would fail the "version at
   175  	// least" test).
   176  	MinVersion string
   177  
   178  	// Not exported, for tests.
   179  	resolver    netResolver
   180  	dialTimeout time.Duration
   181  	connDelay   time.Duration
   182  
   183  	// Snapshot of configured TLS options.
   184  	tlsConfigOpts *TLSConfigOpts
   185  }
   186  
   187  // SignatureHandler is used to sign a nonce from the server while
   188  // authenticating with Nkeys. The callback should sign the nonce and
   189  // return the JWT and the raw signature.
   190  type SignatureHandler func([]byte) (string, []byte, error)
   191  
   192  // RemoteLeafOpts are options for connecting to a remote server as a leaf node.
   193  type RemoteLeafOpts struct {
   194  	LocalAccount      string           `json:"local_account,omitempty"`
   195  	NoRandomize       bool             `json:"-"`
   196  	URLs              []*url.URL       `json:"urls,omitempty"`
   197  	Credentials       string           `json:"-"`
   198  	Nkey              string           `json:"-"`
   199  	SignatureCB       SignatureHandler `json:"-"`
   200  	TLS               bool             `json:"-"`
   201  	TLSConfig         *tls.Config      `json:"-"`
   202  	TLSTimeout        float64          `json:"tls_timeout,omitempty"`
   203  	TLSHandshakeFirst bool             `json:"-"`
   204  	Hub               bool             `json:"hub,omitempty"`
   205  	DenyImports       []string         `json:"-"`
   206  	DenyExports       []string         `json:"-"`
   207  
   208  	// Compression options for this remote. Each remote could have a different
   209  	// setting and also be different from the LeafNode options.
   210  	Compression CompressionOpts `json:"-"`
   211  
   212  	// When an URL has the "ws" (or "wss") scheme, then the server will initiate the
   213  	// connection as a websocket connection. By default, the websocket frames will be
   214  	// masked (as if this server was a websocket client to the remote server). The
   215  	// NoMasking option will change this behavior and will send umasked frames.
   216  	Websocket struct {
   217  		Compression bool `json:"-"`
   218  		NoMasking   bool `json:"-"`
   219  	}
   220  
   221  	tlsConfigOpts *TLSConfigOpts
   222  
   223  	// If we are clustered and our local account has JetStream, if apps are accessing
   224  	// a stream or consumer leader through this LN and it gets dropped, the apps will
   225  	// not be able to work. This tells the system to migrate the leaders away from this server.
   226  	// This only changes leader for R>1 assets.
   227  	JetStreamClusterMigrate bool `json:"jetstream_cluster_migrate,omitempty"`
   228  }
   229  
   230  type JSLimitOpts struct {
   231  	MaxRequestBatch int
   232  	MaxAckPending   int
   233  	MaxHAAssets     int
   234  	Duplicates      time.Duration
   235  }
   236  
   237  type JSTpmOpts struct {
   238  	KeysFile    string
   239  	KeyPassword string
   240  	SrkPassword string
   241  	Pcr         int
   242  }
   243  
   244  // AuthCallout option used to map external AuthN to NATS based AuthZ.
   245  type AuthCallout struct {
   246  	// Must be a public account Nkey.
   247  	Issuer string
   248  	// Account to be used for sending requests.
   249  	Account string
   250  	// Users that will bypass auth_callout and be used for the auth service itself.
   251  	AuthUsers []string
   252  	// XKey is a public xkey for the authorization service.
   253  	// This will enable encryption for server requests and the authorization service responses.
   254  	XKey string
   255  }
   256  
   257  // Options block for nats-server.
   258  // NOTE: This structure is no longer used for monitoring endpoints
   259  // and json tags are deprecated and may be removed in the future.
   260  type Options struct {
   261  	ConfigFile            string        `json:"-"`
   262  	ServerName            string        `json:"server_name"`
   263  	Host                  string        `json:"addr"`
   264  	Port                  int           `json:"port"`
   265  	DontListen            bool          `json:"dont_listen"`
   266  	ClientAdvertise       string        `json:"-"`
   267  	Trace                 bool          `json:"-"`
   268  	Debug                 bool          `json:"-"`
   269  	TraceVerbose          bool          `json:"-"`
   270  	NoLog                 bool          `json:"-"`
   271  	NoSigs                bool          `json:"-"`
   272  	NoSublistCache        bool          `json:"-"`
   273  	NoHeaderSupport       bool          `json:"-"`
   274  	DisableShortFirstPing bool          `json:"-"`
   275  	Logtime               bool          `json:"-"`
   276  	LogtimeUTC            bool          `json:"-"`
   277  	MaxConn               int           `json:"max_connections"`
   278  	MaxSubs               int           `json:"max_subscriptions,omitempty"`
   279  	MaxSubTokens          uint8         `json:"-"`
   280  	Nkeys                 []*NkeyUser   `json:"-"`
   281  	Users                 []*User       `json:"-"`
   282  	Accounts              []*Account    `json:"-"`
   283  	NoAuthUser            string        `json:"-"`
   284  	SystemAccount         string        `json:"-"`
   285  	NoSystemAccount       bool          `json:"-"`
   286  	Username              string        `json:"-"`
   287  	Password              string        `json:"-"`
   288  	Authorization         string        `json:"-"`
   289  	AuthCallout           *AuthCallout  `json:"-"`
   290  	PingInterval          time.Duration `json:"ping_interval"`
   291  	MaxPingsOut           int           `json:"ping_max"`
   292  	HTTPHost              string        `json:"http_host"`
   293  	HTTPPort              int           `json:"http_port"`
   294  	HTTPBasePath          string        `json:"http_base_path"`
   295  	HTTPSPort             int           `json:"https_port"`
   296  	AuthTimeout           float64       `json:"auth_timeout"`
   297  	MaxControlLine        int32         `json:"max_control_line"`
   298  	MaxPayload            int32         `json:"max_payload"`
   299  	MaxPending            int64         `json:"max_pending"`
   300  	Cluster               ClusterOpts   `json:"cluster,omitempty"`
   301  	Gateway               GatewayOpts   `json:"gateway,omitempty"`
   302  	LeafNode              LeafNodeOpts  `json:"leaf,omitempty"`
   303  	JetStream             bool          `json:"jetstream"`
   304  	JetStreamMaxMemory    int64         `json:"-"`
   305  	JetStreamMaxStore     int64         `json:"-"`
   306  	JetStreamDomain       string        `json:"-"`
   307  	JetStreamExtHint      string        `json:"-"`
   308  	JetStreamKey          string        `json:"-"`
   309  	JetStreamOldKey       string        `json:"-"`
   310  	JetStreamCipher       StoreCipher   `json:"-"`
   311  	JetStreamUniqueTag    string
   312  	JetStreamLimits       JSLimitOpts
   313  	JetStreamTpm          JSTpmOpts
   314  	JetStreamMaxCatchup   int64
   315  	StoreDir              string            `json:"-"`
   316  	SyncInterval          time.Duration     `json:"-"`
   317  	SyncAlways            bool              `json:"-"`
   318  	JsAccDefaultDomain    map[string]string `json:"-"` // account to domain name mapping
   319  	Websocket             WebsocketOpts     `json:"-"`
   320  	MQTT                  MQTTOpts          `json:"-"`
   321  	ProfPort              int               `json:"-"`
   322  	ProfBlockRate         int               `json:"-"`
   323  	PidFile               string            `json:"-"`
   324  	PortsFileDir          string            `json:"-"`
   325  	LogFile               string            `json:"-"`
   326  	LogSizeLimit          int64             `json:"-"`
   327  	LogMaxFiles           int64             `json:"-"`
   328  	Syslog                bool              `json:"-"`
   329  	RemoteSyslog          string            `json:"-"`
   330  	Routes                []*url.URL        `json:"-"`
   331  	RoutesStr             string            `json:"-"`
   332  	TLSTimeout            float64           `json:"tls_timeout"`
   333  	TLS                   bool              `json:"-"`
   334  	TLSVerify             bool              `json:"-"`
   335  	TLSMap                bool              `json:"-"`
   336  	TLSCert               string            `json:"-"`
   337  	TLSKey                string            `json:"-"`
   338  	TLSCaCert             string            `json:"-"`
   339  	TLSConfig             *tls.Config       `json:"-"`
   340  	TLSPinnedCerts        PinnedCertSet     `json:"-"`
   341  	TLSRateLimit          int64             `json:"-"`
   342  	// When set to true, the server will perform the TLS handshake before
   343  	// sending the INFO protocol. For clients that are not configured
   344  	// with a similar option, their connection will fail with some sort
   345  	// of timeout or EOF error since they are expecting to receive an
   346  	// INFO protocol first.
   347  	TLSHandshakeFirst bool `json:"-"`
   348  	// If TLSHandshakeFirst is true and this value is strictly positive,
   349  	// the server will wait for that amount of time for the TLS handshake
   350  	// to start before falling back to previous behavior of sending the
   351  	// INFO protocol first. It allows for a mix of newer clients that can
   352  	// require a TLS handshake first, and older clients that can't.
   353  	TLSHandshakeFirstFallback time.Duration `json:"-"`
   354  	AllowNonTLS               bool          `json:"-"`
   355  	WriteDeadline             time.Duration `json:"-"`
   356  	MaxClosedClients          int           `json:"-"`
   357  	LameDuckDuration          time.Duration `json:"-"`
   358  	LameDuckGracePeriod       time.Duration `json:"-"`
   359  
   360  	// MaxTracedMsgLen is the maximum printable length for traced messages.
   361  	MaxTracedMsgLen int `json:"-"`
   362  
   363  	// Operating a trusted NATS server
   364  	TrustedKeys              []string              `json:"-"`
   365  	TrustedOperators         []*jwt.OperatorClaims `json:"-"`
   366  	AccountResolver          AccountResolver       `json:"-"`
   367  	AccountResolverTLSConfig *tls.Config           `json:"-"`
   368  
   369  	// AlwaysEnableNonce will always present a nonce to new connections
   370  	// typically used by custom Authentication implementations who embeds
   371  	// the server and so not presented as a configuration option
   372  	AlwaysEnableNonce bool
   373  
   374  	CustomClientAuthentication Authentication `json:"-"`
   375  	CustomRouterAuthentication Authentication `json:"-"`
   376  
   377  	// CheckConfig configuration file syntax test was successful and exit.
   378  	CheckConfig bool `json:"-"`
   379  
   380  	// DisableJetStreamBanner will not print the ascii art on startup for JetStream enabled servers
   381  	DisableJetStreamBanner bool `json:"-"`
   382  
   383  	// ConnectErrorReports specifies the number of failed attempts
   384  	// at which point server should report the failure of an initial
   385  	// connection to a route, gateway or leaf node.
   386  	// See DEFAULT_CONNECT_ERROR_REPORTS for default value.
   387  	ConnectErrorReports int
   388  
   389  	// ReconnectErrorReports is similar to ConnectErrorReports except
   390  	// that this applies to reconnect events.
   391  	ReconnectErrorReports int
   392  
   393  	// Tags describing the server. They will be included in varz
   394  	// and used as a filter criteria for some system requests.
   395  	Tags jwt.TagList `json:"-"`
   396  
   397  	// OCSPConfig enables OCSP Stapling in the server.
   398  	OCSPConfig    *OCSPConfig
   399  	tlsConfigOpts *TLSConfigOpts
   400  
   401  	// private fields, used to know if bool options are explicitly
   402  	// defined in config and/or command line params.
   403  	inConfig  map[string]bool
   404  	inCmdLine map[string]bool
   405  
   406  	// private fields for operator mode
   407  	operatorJWT            []string
   408  	resolverPreloads       map[string]string
   409  	resolverPinnedAccounts map[string]struct{}
   410  
   411  	// private fields, used for testing
   412  	gatewaysSolicitDelay time.Duration
   413  	overrideProto        int
   414  
   415  	// JetStream
   416  	maxMemSet   bool
   417  	maxStoreSet bool
   418  	syncSet     bool
   419  
   420  	// OCSP Cache config enables next-gen cache for OCSP features
   421  	OCSPCacheConfig *OCSPResponseCacheConfig
   422  
   423  	// Used to mark that we had a top level authorization block.
   424  	authBlockDefined bool
   425  }
   426  
   427  // WebsocketOpts are options for websocket
   428  type WebsocketOpts struct {
   429  	// The server will accept websocket client connections on this hostname/IP.
   430  	Host string
   431  	// The server will accept websocket client connections on this port.
   432  	Port int
   433  	// The host:port to advertise to websocket clients in the cluster.
   434  	Advertise string
   435  
   436  	// If no user name is provided when a client connects, will default to the
   437  	// matching user from the global list of users in `Options.Users`.
   438  	NoAuthUser string
   439  
   440  	// Name of the cookie, which if present in WebSocket upgrade headers,
   441  	// will be treated as JWT during CONNECT phase as long as
   442  	// "jwt" specified in the CONNECT options is missing or empty.
   443  	JWTCookie string
   444  
   445  	// Name of the cookie, which if present in WebSocket upgrade headers,
   446  	// will be treated as Username during CONNECT phase as long as
   447  	// "user" specified in the CONNECT options is missing or empty.
   448  	UsernameCookie string
   449  
   450  	// Name of the cookie, which if present in WebSocket upgrade headers,
   451  	// will be treated as Password during CONNECT phase as long as
   452  	// "pass" specified in the CONNECT options is missing or empty.
   453  	PasswordCookie string
   454  
   455  	// Name of the cookie, which if present in WebSocket upgrade headers,
   456  	// will be treated as Token during CONNECT phase as long as
   457  	// "auth_token" specified in the CONNECT options is missing or empty.
   458  	// Note that when this is useful for passing a JWT to an cuth callout
   459  	// when the server uses delegated authentication ("operator mode") or
   460  	// when using delegated authentication, but the auth callout validates some
   461  	// other JWT or string. Note that this does map to an actual server-wide
   462  	// "auth_token", note that using it for that purpose is greatly discouraged.
   463  	TokenCookie string
   464  
   465  	// Authentication section. If anything is configured in this section,
   466  	// it will override the authorization configuration of regular clients.
   467  	Username string
   468  	Password string
   469  	Token    string
   470  
   471  	// Timeout for the authentication process.
   472  	AuthTimeout float64
   473  
   474  	// By default the server will enforce the use of TLS. If no TLS configuration
   475  	// is provided, you need to explicitly set NoTLS to true to allow the server
   476  	// to start without TLS configuration. Note that if a TLS configuration is
   477  	// present, this boolean is ignored and the server will run the Websocket
   478  	// server with that TLS configuration.
   479  	// Running without TLS is less secure since Websocket clients that use bearer
   480  	// tokens will send them in clear. So this should not be used in production.
   481  	NoTLS bool
   482  
   483  	// TLS configuration is required.
   484  	TLSConfig *tls.Config
   485  	// If true, map certificate values for authentication purposes.
   486  	TLSMap bool
   487  
   488  	// When present, accepted client certificates (verify/verify_and_map) must be in this list
   489  	TLSPinnedCerts PinnedCertSet
   490  
   491  	// If true, the Origin header must match the request's host.
   492  	SameOrigin bool
   493  
   494  	// Only origins in this list will be accepted. If empty and
   495  	// SameOrigin is false, any origin is accepted.
   496  	AllowedOrigins []string
   497  
   498  	// If set to true, the server will negotiate with clients
   499  	// if compression can be used. If this is false, no compression
   500  	// will be used (both in server and clients) since it has to
   501  	// be negotiated between both endpoints
   502  	Compression bool
   503  
   504  	// Total time allowed for the server to read the client request
   505  	// and write the response back to the client. This include the
   506  	// time needed for the TLS Handshake.
   507  	HandshakeTimeout time.Duration
   508  
   509  	// Headers to be added to the upgrade response.
   510  	// Useful for adding custom headers like Strict-Transport-Security.
   511  	Headers map[string]string
   512  
   513  	// Snapshot of configured TLS options.
   514  	tlsConfigOpts *TLSConfigOpts
   515  }
   516  
   517  // MQTTOpts are options for MQTT
   518  type MQTTOpts struct {
   519  	// The server will accept MQTT client connections on this hostname/IP.
   520  	Host string
   521  	// The server will accept MQTT client connections on this port.
   522  	Port int
   523  
   524  	// If no user name is provided when a client connects, will default to the
   525  	// matching user from the global list of users in `Options.Users`.
   526  	NoAuthUser string
   527  
   528  	// Authentication section. If anything is configured in this section,
   529  	// it will override the authorization configuration of regular clients.
   530  	Username string
   531  	Password string
   532  	Token    string
   533  
   534  	// JetStream domain mqtt is supposed to pick up
   535  	JsDomain string
   536  
   537  	// Number of replicas for MQTT streams.
   538  	// Negative or 0 value means that the server(s) will pick a replica
   539  	// number based on the known size of the cluster (but capped at 3).
   540  	// Note that if an account was already connected, the stream's replica
   541  	// count is not modified. Use the NATS CLI to update the count if desired.
   542  	StreamReplicas int
   543  
   544  	// Number of replicas for MQTT consumers.
   545  	// Negative or 0 value means that there is no override and the consumer
   546  	// will have the same replica factor that the stream it belongs to.
   547  	// If a value is specified, it will require to be lower than the stream
   548  	// replicas count (lower than StreamReplicas if specified, but also lower
   549  	// than the automatic value determined by cluster size).
   550  	// Note that existing consumers are not modified.
   551  	//
   552  	// UPDATE: This is no longer used while messages stream has interest policy retention
   553  	// which requires consumer replica count to match the parent stream.
   554  	ConsumerReplicas int
   555  
   556  	// Indicate if the consumers should be created with memory storage.
   557  	// Note that existing consumers are not modified.
   558  	ConsumerMemoryStorage bool
   559  
   560  	// If specified will have the system auto-cleanup the consumers after being
   561  	// inactive for the specified amount of time.
   562  	ConsumerInactiveThreshold time.Duration
   563  
   564  	// Timeout for the authentication process.
   565  	AuthTimeout float64
   566  
   567  	// TLS configuration is required.
   568  	TLSConfig *tls.Config
   569  	// If true, map certificate values for authentication purposes.
   570  	TLSMap bool
   571  	// Timeout for the TLS handshake
   572  	TLSTimeout float64
   573  	// Set of allowable certificates
   574  	TLSPinnedCerts PinnedCertSet
   575  
   576  	// AckWait is the amount of time after which a QoS 1 or 2 message sent to a
   577  	// client is redelivered as a DUPLICATE if the server has not received the
   578  	// PUBACK on the original Packet Identifier. The same value applies to
   579  	// PubRel redelivery. The value has to be positive. Zero will cause the
   580  	// server to use the default value (30 seconds). Note that changes to this
   581  	// option is applied only to new MQTT subscriptions (or sessions for
   582  	// PubRels).
   583  	AckWait time.Duration
   584  
   585  	// MaxAckPending is the amount of QoS 1 and 2 messages (combined) the server
   586  	// can send to a subscription without receiving any PUBACK for those
   587  	// messages. The valid range is [0..65535].
   588  	//
   589  	// The total of subscriptions' MaxAckPending on a given session cannot
   590  	// exceed 65535. Attempting to create a subscription that would bring the
   591  	// total above the limit would result in the server returning 0x80 in the
   592  	// SUBACK for this subscription.
   593  	//
   594  	// Due to how the NATS Server handles the MQTT "#" wildcard, each
   595  	// subscription ending with "#" will use 2 times the MaxAckPending value.
   596  	// Note that changes to this option is applied only to new subscriptions.
   597  	MaxAckPending uint16
   598  
   599  	// Snapshot of configured TLS options.
   600  	tlsConfigOpts *TLSConfigOpts
   601  
   602  	// rejectQoS2Pub tells the MQTT client to not accept QoS2 PUBLISH, instead
   603  	// error and terminate the connection.
   604  	rejectQoS2Pub bool
   605  
   606  	// downgradeQOS2Sub tells the MQTT client to downgrade QoS2 SUBSCRIBE
   607  	// requests to QoS1.
   608  	downgradeQoS2Sub bool
   609  }
   610  
   611  type netResolver interface {
   612  	LookupHost(ctx context.Context, host string) ([]string, error)
   613  }
   614  
   615  // Clone performs a deep copy of the Options struct, returning a new clone
   616  // with all values copied.
   617  func (o *Options) Clone() *Options {
   618  	if o == nil {
   619  		return nil
   620  	}
   621  	clone := &Options{}
   622  	*clone = *o
   623  	if o.Users != nil {
   624  		clone.Users = make([]*User, len(o.Users))
   625  		for i, user := range o.Users {
   626  			clone.Users[i] = user.clone()
   627  		}
   628  	}
   629  	if o.Nkeys != nil {
   630  		clone.Nkeys = make([]*NkeyUser, len(o.Nkeys))
   631  		for i, nkey := range o.Nkeys {
   632  			clone.Nkeys[i] = nkey.clone()
   633  		}
   634  	}
   635  
   636  	if o.Routes != nil {
   637  		clone.Routes = deepCopyURLs(o.Routes)
   638  	}
   639  	if o.TLSConfig != nil {
   640  		clone.TLSConfig = o.TLSConfig.Clone()
   641  	}
   642  	if o.Cluster.TLSConfig != nil {
   643  		clone.Cluster.TLSConfig = o.Cluster.TLSConfig.Clone()
   644  	}
   645  	if o.Gateway.TLSConfig != nil {
   646  		clone.Gateway.TLSConfig = o.Gateway.TLSConfig.Clone()
   647  	}
   648  	if len(o.Gateway.Gateways) > 0 {
   649  		clone.Gateway.Gateways = make([]*RemoteGatewayOpts, len(o.Gateway.Gateways))
   650  		for i, g := range o.Gateway.Gateways {
   651  			clone.Gateway.Gateways[i] = g.clone()
   652  		}
   653  	}
   654  	// FIXME(dlc) - clone leaf node stuff.
   655  	return clone
   656  }
   657  
   658  func deepCopyURLs(urls []*url.URL) []*url.URL {
   659  	if urls == nil {
   660  		return nil
   661  	}
   662  	curls := make([]*url.URL, len(urls))
   663  	for i, u := range urls {
   664  		cu := &url.URL{}
   665  		*cu = *u
   666  		curls[i] = cu
   667  	}
   668  	return curls
   669  }
   670  
   671  // Configuration file authorization section.
   672  type authorization struct {
   673  	// Singles
   674  	user  string
   675  	pass  string
   676  	token string
   677  	nkey  string
   678  	acc   string
   679  	// Multiple Nkeys/Users
   680  	nkeys              []*NkeyUser
   681  	users              []*User
   682  	timeout            float64
   683  	defaultPermissions *Permissions
   684  	// Auth Callouts
   685  	callout *AuthCallout
   686  }
   687  
   688  // TLSConfigOpts holds the parsed tls config information,
   689  // used with flag parsing
   690  type TLSConfigOpts struct {
   691  	CertFile          string
   692  	KeyFile           string
   693  	CaFile            string
   694  	Verify            bool
   695  	Insecure          bool
   696  	Map               bool
   697  	TLSCheckKnownURLs bool
   698  	HandshakeFirst    bool          // Indicate that the TLS handshake should occur first, before sending the INFO protocol.
   699  	FallbackDelay     time.Duration // Where supported, indicates how long to wait for the handshake before falling back to sending the INFO protocol first.
   700  	Timeout           float64
   701  	RateLimit         int64
   702  	Ciphers           []uint16
   703  	CurvePreferences  []tls.CurveID
   704  	PinnedCerts       PinnedCertSet
   705  	CertStore         certstore.StoreType
   706  	CertMatchBy       certstore.MatchByType
   707  	CertMatch         string
   708  	CaCertsMatch      []string
   709  	OCSPPeerConfig    *certidp.OCSPPeerConfig
   710  	Certificates      []*TLSCertPairOpt
   711  }
   712  
   713  // TLSCertPairOpt are the paths to a certificate and private key.
   714  type TLSCertPairOpt struct {
   715  	CertFile string
   716  	KeyFile  string
   717  }
   718  
   719  // OCSPConfig represents the options of OCSP stapling options.
   720  type OCSPConfig struct {
   721  	// Mode defines the policy for OCSP stapling.
   722  	Mode OCSPMode
   723  
   724  	// OverrideURLs is the http URL endpoint used to get OCSP staples.
   725  	OverrideURLs []string
   726  }
   727  
   728  var tlsUsage = `
   729  TLS configuration is specified in the tls section of a configuration file:
   730  
   731  e.g.
   732  
   733      tls {
   734          cert_file:      "./certs/server-cert.pem"
   735          key_file:       "./certs/server-key.pem"
   736          ca_file:        "./certs/ca.pem"
   737          verify:         true
   738          verify_and_map: true
   739  
   740          cipher_suites: [
   741              "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
   742              "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
   743          ]
   744          curve_preferences: [
   745              "CurveP256",
   746              "CurveP384",
   747              "CurveP521"
   748          ]
   749      }
   750  
   751  Available cipher suites include:
   752  `
   753  
   754  // ProcessConfigFile processes a configuration file.
   755  // FIXME(dlc): A bit hacky
   756  func ProcessConfigFile(configFile string) (*Options, error) {
   757  	opts := &Options{}
   758  	if err := opts.ProcessConfigFile(configFile); err != nil {
   759  		// If only warnings then continue and return the options.
   760  		if cerr, ok := err.(*processConfigErr); ok && len(cerr.Errors()) == 0 {
   761  			return opts, nil
   762  		}
   763  
   764  		return nil, err
   765  	}
   766  	return opts, nil
   767  }
   768  
   769  // token is an item parsed from the configuration.
   770  type token interface {
   771  	Value() any
   772  	Line() int
   773  	IsUsedVariable() bool
   774  	SourceFile() string
   775  	Position() int
   776  }
   777  
   778  // unwrapValue can be used to get the token and value from an item
   779  // to be able to report the line number in case of an incorrect
   780  // configuration.
   781  // also stores the token in lastToken for use in convertPanicToError
   782  func unwrapValue(v any, lastToken *token) (token, any) {
   783  	switch tk := v.(type) {
   784  	case token:
   785  		if lastToken != nil {
   786  			*lastToken = tk
   787  		}
   788  		return tk, tk.Value()
   789  	default:
   790  		return nil, v
   791  	}
   792  }
   793  
   794  // use in defer to recover from panic and turn it into an error associated with last token
   795  func convertPanicToErrorList(lastToken *token, errors *[]error) {
   796  	// only recover if an error can be stored
   797  	if errors == nil {
   798  		return
   799  	} else if err := recover(); err == nil {
   800  		return
   801  	} else if lastToken != nil && *lastToken != nil {
   802  		*errors = append(*errors, &configErr{*lastToken, fmt.Sprint(err)})
   803  	} else {
   804  		*errors = append(*errors, fmt.Errorf("encountered panic without a token %v", err))
   805  	}
   806  }
   807  
   808  // use in defer to recover from panic and turn it into an error associated with last token
   809  func convertPanicToError(lastToken *token, e *error) {
   810  	// only recover if an error can be stored
   811  	if e == nil || *e != nil {
   812  		return
   813  	} else if err := recover(); err == nil {
   814  		return
   815  	} else if lastToken != nil && *lastToken != nil {
   816  		*e = &configErr{*lastToken, fmt.Sprint(err)}
   817  	} else {
   818  		*e = fmt.Errorf("%v", err)
   819  	}
   820  }
   821  
   822  // configureSystemAccount configures a system account
   823  // if present in the configuration.
   824  func configureSystemAccount(o *Options, m map[string]any) (retErr error) {
   825  	var lt token
   826  	defer convertPanicToError(&lt, &retErr)
   827  	configure := func(v any) error {
   828  		tk, v := unwrapValue(v, &lt)
   829  		sa, ok := v.(string)
   830  		if !ok {
   831  			return &configErr{tk, "system account name must be a string"}
   832  		}
   833  		o.SystemAccount = sa
   834  		return nil
   835  	}
   836  
   837  	if v, ok := m["system_account"]; ok {
   838  		return configure(v)
   839  	} else if v, ok := m["system"]; ok {
   840  		return configure(v)
   841  	}
   842  
   843  	return nil
   844  }
   845  
   846  // ProcessConfigFile updates the Options structure with options
   847  // present in the given configuration file.
   848  // This version is convenient if one wants to set some default
   849  // options and then override them with what is in the config file.
   850  // For instance, this version allows you to do something such as:
   851  //
   852  // opts := &Options{Debug: true}
   853  // opts.ProcessConfigFile(myConfigFile)
   854  //
   855  // If the config file contains "debug: false", after this call,
   856  // opts.Debug would really be false. It would be impossible to
   857  // achieve that with the non receiver ProcessConfigFile() version,
   858  // since one would not know after the call if "debug" was not present
   859  // or was present but set to false.
   860  func (o *Options) ProcessConfigFile(configFile string) error {
   861  	o.ConfigFile = configFile
   862  	if configFile == _EMPTY_ {
   863  		return nil
   864  	}
   865  	m, err := conf.ParseFileWithChecks(configFile)
   866  	if err != nil {
   867  		return err
   868  	}
   869  	// Collect all errors and warnings and report them all together.
   870  	errors := make([]error, 0)
   871  	warnings := make([]error, 0)
   872  	if len(m) == 0 {
   873  		warnings = append(warnings, fmt.Errorf("%s: config has no values or is empty", configFile))
   874  	}
   875  
   876  	// First check whether a system account has been defined,
   877  	// as that is a condition for other features to be enabled.
   878  	if err := configureSystemAccount(o, m); err != nil {
   879  		errors = append(errors, err)
   880  	}
   881  
   882  	for k, v := range m {
   883  		o.processConfigFileLine(k, v, &errors, &warnings)
   884  	}
   885  
   886  	if len(errors) > 0 || len(warnings) > 0 {
   887  		return &processConfigErr{
   888  			errors:   errors,
   889  			warnings: warnings,
   890  		}
   891  	}
   892  
   893  	return nil
   894  }
   895  
   896  func (o *Options) processConfigFileLine(k string, v any, errors *[]error, warnings *[]error) {
   897  	var lt token
   898  	defer convertPanicToErrorList(&lt, errors)
   899  
   900  	tk, v := unwrapValue(v, &lt)
   901  	switch strings.ToLower(k) {
   902  	case "listen":
   903  		hp, err := parseListen(v)
   904  		if err != nil {
   905  			*errors = append(*errors, &configErr{tk, err.Error()})
   906  			return
   907  		}
   908  		o.Host = hp.host
   909  		o.Port = hp.port
   910  	case "client_advertise":
   911  		o.ClientAdvertise = v.(string)
   912  	case "port":
   913  		o.Port = int(v.(int64))
   914  	case "server_name":
   915  		o.ServerName = v.(string)
   916  	case "host", "net":
   917  		o.Host = v.(string)
   918  	case "debug":
   919  		o.Debug = v.(bool)
   920  		trackExplicitVal(&o.inConfig, "Debug", o.Debug)
   921  	case "trace":
   922  		o.Trace = v.(bool)
   923  		trackExplicitVal(&o.inConfig, "Trace", o.Trace)
   924  	case "trace_verbose":
   925  		o.TraceVerbose = v.(bool)
   926  		o.Trace = v.(bool)
   927  		trackExplicitVal(&o.inConfig, "TraceVerbose", o.TraceVerbose)
   928  		trackExplicitVal(&o.inConfig, "Trace", o.Trace)
   929  	case "logtime":
   930  		o.Logtime = v.(bool)
   931  		trackExplicitVal(&o.inConfig, "Logtime", o.Logtime)
   932  	case "logtime_utc":
   933  		o.LogtimeUTC = v.(bool)
   934  		trackExplicitVal(&o.inConfig, "LogtimeUTC", o.LogtimeUTC)
   935  	case "mappings", "maps":
   936  		gacc := NewAccount(globalAccountName)
   937  		o.Accounts = append(o.Accounts, gacc)
   938  		err := parseAccountMappings(tk, gacc, errors)
   939  		if err != nil {
   940  			*errors = append(*errors, err)
   941  			return
   942  		}
   943  	case "disable_sublist_cache", "no_sublist_cache":
   944  		o.NoSublistCache = v.(bool)
   945  	case "accounts":
   946  		err := parseAccounts(tk, o, errors, warnings)
   947  		if err != nil {
   948  			*errors = append(*errors, err)
   949  			return
   950  		}
   951  	case "authorization":
   952  		auth, err := parseAuthorization(tk, errors)
   953  		if err != nil {
   954  			*errors = append(*errors, err)
   955  			return
   956  		}
   957  		o.authBlockDefined = true
   958  		o.Username = auth.user
   959  		o.Password = auth.pass
   960  		o.Authorization = auth.token
   961  		o.AuthTimeout = auth.timeout
   962  		o.AuthCallout = auth.callout
   963  
   964  		if (auth.user != _EMPTY_ || auth.pass != _EMPTY_) && auth.token != _EMPTY_ {
   965  			err := &configErr{tk, "Cannot have a user/pass and token"}
   966  			*errors = append(*errors, err)
   967  			return
   968  		}
   969  		// In case parseAccounts() was done first, we need to check for duplicates.
   970  		unames := setupUsersAndNKeysDuplicateCheckMap(o)
   971  		// Check for multiple users defined.
   972  		// Note: auth.users will be != nil as long as `users: []` is present
   973  		// in the authorization block, even if empty, and will also account for
   974  		// nkey users. We also check for users/nkeys that may have been already
   975  		// added in parseAccounts() (which means they will be in unames)
   976  		if auth.users != nil || len(unames) > 0 {
   977  			if auth.user != _EMPTY_ {
   978  				err := &configErr{tk, "Can not have a single user/pass and a users array"}
   979  				*errors = append(*errors, err)
   980  				return
   981  			}
   982  			if auth.token != _EMPTY_ {
   983  				err := &configErr{tk, "Can not have a token and a users array"}
   984  				*errors = append(*errors, err)
   985  				return
   986  			}
   987  			// Now check that if we have users, there is no duplicate, including
   988  			// users that may have been configured in parseAccounts().
   989  			if len(auth.users) > 0 {
   990  				for _, u := range auth.users {
   991  					if _, ok := unames[u.Username]; ok {
   992  						err := &configErr{tk, fmt.Sprintf("Duplicate user %q detected", u.Username)}
   993  						*errors = append(*errors, err)
   994  						return
   995  					}
   996  					unames[u.Username] = struct{}{}
   997  				}
   998  				// Users may have been added from Accounts parsing, so do an append here
   999  				o.Users = append(o.Users, auth.users...)
  1000  			}
  1001  		}
  1002  		// Check for nkeys
  1003  		if len(auth.nkeys) > 0 {
  1004  			for _, u := range auth.nkeys {
  1005  				if _, ok := unames[u.Nkey]; ok {
  1006  					err := &configErr{tk, fmt.Sprintf("Duplicate nkey %q detected", u.Nkey)}
  1007  					*errors = append(*errors, err)
  1008  					return
  1009  				}
  1010  				unames[u.Nkey] = struct{}{}
  1011  			}
  1012  			// NKeys may have been added from Accounts parsing, so do an append here
  1013  			o.Nkeys = append(o.Nkeys, auth.nkeys...)
  1014  		}
  1015  	case "http":
  1016  		hp, err := parseListen(v)
  1017  		if err != nil {
  1018  			err := &configErr{tk, err.Error()}
  1019  			*errors = append(*errors, err)
  1020  			return
  1021  		}
  1022  		o.HTTPHost = hp.host
  1023  		o.HTTPPort = hp.port
  1024  	case "https":
  1025  		hp, err := parseListen(v)
  1026  		if err != nil {
  1027  			err := &configErr{tk, err.Error()}
  1028  			*errors = append(*errors, err)
  1029  			return
  1030  		}
  1031  		o.HTTPHost = hp.host
  1032  		o.HTTPSPort = hp.port
  1033  	case "http_port", "monitor_port":
  1034  		o.HTTPPort = int(v.(int64))
  1035  	case "https_port":
  1036  		o.HTTPSPort = int(v.(int64))
  1037  	case "http_base_path":
  1038  		o.HTTPBasePath = v.(string)
  1039  	case "cluster":
  1040  		err := parseCluster(tk, o, errors, warnings)
  1041  		if err != nil {
  1042  			*errors = append(*errors, err)
  1043  			return
  1044  		}
  1045  	case "gateway":
  1046  		if err := parseGateway(tk, o, errors, warnings); err != nil {
  1047  			*errors = append(*errors, err)
  1048  			return
  1049  		}
  1050  	case "leaf", "leafnodes":
  1051  		err := parseLeafNodes(tk, o, errors, warnings)
  1052  		if err != nil {
  1053  			*errors = append(*errors, err)
  1054  			return
  1055  		}
  1056  	case "store_dir", "storedir":
  1057  		// Check if JetStream configuration is also setting the storage directory.
  1058  		if o.StoreDir != _EMPTY_ {
  1059  			*errors = append(*errors, &configErr{tk, "Duplicate 'store_dir' configuration"})
  1060  			return
  1061  		}
  1062  		o.StoreDir = v.(string)
  1063  	case "jetstream":
  1064  		err := parseJetStream(tk, o, errors, warnings)
  1065  		if err != nil {
  1066  			*errors = append(*errors, err)
  1067  			return
  1068  		}
  1069  	case "logfile", "log_file":
  1070  		o.LogFile = v.(string)
  1071  	case "logfile_size_limit", "log_size_limit":
  1072  		o.LogSizeLimit = v.(int64)
  1073  	case "logfile_max_num", "log_max_num":
  1074  		o.LogMaxFiles = v.(int64)
  1075  	case "syslog":
  1076  		o.Syslog = v.(bool)
  1077  		trackExplicitVal(&o.inConfig, "Syslog", o.Syslog)
  1078  	case "remote_syslog":
  1079  		o.RemoteSyslog = v.(string)
  1080  	case "pidfile", "pid_file":
  1081  		o.PidFile = v.(string)
  1082  	case "ports_file_dir":
  1083  		o.PortsFileDir = v.(string)
  1084  	case "prof_port":
  1085  		o.ProfPort = int(v.(int64))
  1086  	case "prof_block_rate":
  1087  		o.ProfBlockRate = int(v.(int64))
  1088  	case "max_control_line":
  1089  		if v.(int64) > 1<<31-1 {
  1090  			err := &configErr{tk, fmt.Sprintf("%s value is too big", k)}
  1091  			*errors = append(*errors, err)
  1092  			return
  1093  		}
  1094  		o.MaxControlLine = int32(v.(int64))
  1095  	case "max_payload":
  1096  		if v.(int64) > 1<<31-1 {
  1097  			err := &configErr{tk, fmt.Sprintf("%s value is too big", k)}
  1098  			*errors = append(*errors, err)
  1099  			return
  1100  		}
  1101  		o.MaxPayload = int32(v.(int64))
  1102  	case "max_pending":
  1103  		o.MaxPending = v.(int64)
  1104  	case "max_connections", "max_conn":
  1105  		o.MaxConn = int(v.(int64))
  1106  	case "max_traced_msg_len":
  1107  		o.MaxTracedMsgLen = int(v.(int64))
  1108  	case "max_subscriptions", "max_subs":
  1109  		o.MaxSubs = int(v.(int64))
  1110  	case "max_sub_tokens", "max_subscription_tokens":
  1111  		if n := v.(int64); n > math.MaxUint8 {
  1112  			err := &configErr{tk, fmt.Sprintf("%s value is too big", k)}
  1113  			*errors = append(*errors, err)
  1114  			return
  1115  		} else if n <= 0 {
  1116  			err := &configErr{tk, fmt.Sprintf("%s value can not be negative", k)}
  1117  			*errors = append(*errors, err)
  1118  			return
  1119  		} else {
  1120  			o.MaxSubTokens = uint8(n)
  1121  		}
  1122  	case "ping_interval":
  1123  		o.PingInterval = parseDuration("ping_interval", tk, v, errors, warnings)
  1124  	case "ping_max":
  1125  		o.MaxPingsOut = int(v.(int64))
  1126  	case "tls":
  1127  		tc, err := parseTLS(tk, true)
  1128  		if err != nil {
  1129  			*errors = append(*errors, err)
  1130  			return
  1131  		}
  1132  		if o.TLSConfig, err = GenTLSConfig(tc); err != nil {
  1133  			err := &configErr{tk, err.Error()}
  1134  			*errors = append(*errors, err)
  1135  			return
  1136  		}
  1137  		o.TLSTimeout = tc.Timeout
  1138  		o.TLSMap = tc.Map
  1139  		o.TLSPinnedCerts = tc.PinnedCerts
  1140  		o.TLSRateLimit = tc.RateLimit
  1141  		o.TLSHandshakeFirst = tc.HandshakeFirst
  1142  		o.TLSHandshakeFirstFallback = tc.FallbackDelay
  1143  
  1144  		// Need to keep track of path of the original TLS config
  1145  		// and certs path for OCSP Stapling monitoring.
  1146  		o.tlsConfigOpts = tc
  1147  	case "ocsp":
  1148  		switch vv := v.(type) {
  1149  		case bool:
  1150  			if vv {
  1151  				// Default is Auto which honors Must Staple status request
  1152  				// but does not shutdown the server in case it is revoked,
  1153  				// letting the client choose whether to trust or not the server.
  1154  				o.OCSPConfig = &OCSPConfig{Mode: OCSPModeAuto}
  1155  			} else {
  1156  				o.OCSPConfig = &OCSPConfig{Mode: OCSPModeNever}
  1157  			}
  1158  		case map[string]any:
  1159  			ocsp := &OCSPConfig{Mode: OCSPModeAuto}
  1160  
  1161  			for kk, kv := range vv {
  1162  				_, v = unwrapValue(kv, &tk)
  1163  				switch kk {
  1164  				case "mode":
  1165  					mode := v.(string)
  1166  					switch {
  1167  					case strings.EqualFold(mode, "always"):
  1168  						ocsp.Mode = OCSPModeAlways
  1169  					case strings.EqualFold(mode, "must"):
  1170  						ocsp.Mode = OCSPModeMust
  1171  					case strings.EqualFold(mode, "never"):
  1172  						ocsp.Mode = OCSPModeNever
  1173  					case strings.EqualFold(mode, "auto"):
  1174  						ocsp.Mode = OCSPModeAuto
  1175  					default:
  1176  						*errors = append(*errors, &configErr{tk, fmt.Sprintf("error parsing ocsp config: unsupported ocsp mode %T", mode)})
  1177  					}
  1178  				case "urls":
  1179  					urls := v.([]string)
  1180  					ocsp.OverrideURLs = urls
  1181  				case "url":
  1182  					url := v.(string)
  1183  					ocsp.OverrideURLs = []string{url}
  1184  				default:
  1185  					*errors = append(*errors, &configErr{tk, fmt.Sprintf("error parsing ocsp config: unsupported field %T", kk)})
  1186  					return
  1187  				}
  1188  			}
  1189  			o.OCSPConfig = ocsp
  1190  		default:
  1191  			*errors = append(*errors, &configErr{tk, fmt.Sprintf("error parsing ocsp config: unsupported type %T", v)})
  1192  			return
  1193  		}
  1194  	case "allow_non_tls":
  1195  		o.AllowNonTLS = v.(bool)
  1196  	case "write_deadline":
  1197  		o.WriteDeadline = parseDuration("write_deadline", tk, v, errors, warnings)
  1198  	case "lame_duck_duration":
  1199  		dur, err := time.ParseDuration(v.(string))
  1200  		if err != nil {
  1201  			err := &configErr{tk, fmt.Sprintf("error parsing lame_duck_duration: %v", err)}
  1202  			*errors = append(*errors, err)
  1203  			return
  1204  		}
  1205  		if dur < 30*time.Second {
  1206  			err := &configErr{tk, fmt.Sprintf("invalid lame_duck_duration of %v, minimum is 30 seconds", dur)}
  1207  			*errors = append(*errors, err)
  1208  			return
  1209  		}
  1210  		o.LameDuckDuration = dur
  1211  	case "lame_duck_grace_period":
  1212  		dur, err := time.ParseDuration(v.(string))
  1213  		if err != nil {
  1214  			err := &configErr{tk, fmt.Sprintf("error parsing lame_duck_grace_period: %v", err)}
  1215  			*errors = append(*errors, err)
  1216  			return
  1217  		}
  1218  		if dur < 0 {
  1219  			err := &configErr{tk, "invalid lame_duck_grace_period, needs to be positive"}
  1220  			*errors = append(*errors, err)
  1221  			return
  1222  		}
  1223  		o.LameDuckGracePeriod = dur
  1224  	case "operator", "operators", "roots", "root", "root_operators", "root_operator":
  1225  		opFiles := []string{}
  1226  		switch v := v.(type) {
  1227  		case string:
  1228  			opFiles = append(opFiles, v)
  1229  		case []string:
  1230  			opFiles = append(opFiles, v...)
  1231  		default:
  1232  			err := &configErr{tk, fmt.Sprintf("error parsing operators: unsupported type %T", v)}
  1233  			*errors = append(*errors, err)
  1234  		}
  1235  		// Assume for now these are file names, but they can also be the JWT itself inline.
  1236  		o.TrustedOperators = make([]*jwt.OperatorClaims, 0, len(opFiles))
  1237  		for _, fname := range opFiles {
  1238  			theJWT, opc, err := readOperatorJWT(fname)
  1239  			if err != nil {
  1240  				err := &configErr{tk, fmt.Sprintf("error parsing operator JWT: %v", err)}
  1241  				*errors = append(*errors, err)
  1242  				continue
  1243  			}
  1244  			o.operatorJWT = append(o.operatorJWT, theJWT)
  1245  			o.TrustedOperators = append(o.TrustedOperators, opc)
  1246  		}
  1247  		if len(o.TrustedOperators) == 1 {
  1248  			// In case "resolver" is defined as well, it takes precedence
  1249  			if o.AccountResolver == nil {
  1250  				if accUrl, err := parseURL(o.TrustedOperators[0].AccountServerURL, "account resolver"); err == nil {
  1251  					// nsc automatically appends "/accounts" during nsc push
  1252  					o.AccountResolver, _ = NewURLAccResolver(accUrl.String() + "/accounts")
  1253  				}
  1254  			}
  1255  			// In case "system_account" is defined as well, it takes precedence
  1256  			if o.SystemAccount == _EMPTY_ {
  1257  				o.SystemAccount = o.TrustedOperators[0].SystemAccount
  1258  			}
  1259  		}
  1260  	case "resolver", "account_resolver", "accounts_resolver":
  1261  		switch v := v.(type) {
  1262  		case string:
  1263  			// "resolver" takes precedence over value obtained from "operator".
  1264  			// Clear so that parsing errors are not silently ignored.
  1265  			o.AccountResolver = nil
  1266  			memResolverRe := regexp.MustCompile(`(?i)(MEM|MEMORY)\s*`)
  1267  			resolverRe := regexp.MustCompile(`(?i)(?:URL){1}(?:\({1}\s*"?([^\s"]*)"?\s*\){1})?\s*`)
  1268  			if memResolverRe.MatchString(v) {
  1269  				o.AccountResolver = &MemAccResolver{}
  1270  			} else if items := resolverRe.FindStringSubmatch(v); len(items) == 2 {
  1271  				url := items[1]
  1272  				_, err := parseURL(url, "account resolver")
  1273  				if err != nil {
  1274  					*errors = append(*errors, &configErr{tk, err.Error()})
  1275  					return
  1276  				}
  1277  				if ur, err := NewURLAccResolver(url); err != nil {
  1278  					err := &configErr{tk, err.Error()}
  1279  					*errors = append(*errors, err)
  1280  					return
  1281  				} else {
  1282  					o.AccountResolver = ur
  1283  				}
  1284  			}
  1285  		case map[string]any:
  1286  			del := false
  1287  			hdel := false
  1288  			hdel_set := false
  1289  			dir := _EMPTY_
  1290  			dirType := _EMPTY_
  1291  			limit := int64(0)
  1292  			ttl := time.Duration(0)
  1293  			sync := time.Duration(0)
  1294  			opts := []DirResOption{}
  1295  			var err error
  1296  			if v, ok := v["dir"]; ok {
  1297  				_, v := unwrapValue(v, &lt)
  1298  				dir = v.(string)
  1299  			}
  1300  			if v, ok := v["type"]; ok {
  1301  				_, v := unwrapValue(v, &lt)
  1302  				dirType = v.(string)
  1303  			}
  1304  			if v, ok := v["allow_delete"]; ok {
  1305  				_, v := unwrapValue(v, &lt)
  1306  				del = v.(bool)
  1307  			}
  1308  			if v, ok := v["hard_delete"]; ok {
  1309  				_, v := unwrapValue(v, &lt)
  1310  				hdel_set = true
  1311  				hdel = v.(bool)
  1312  			}
  1313  			if v, ok := v["limit"]; ok {
  1314  				_, v := unwrapValue(v, &lt)
  1315  				limit = v.(int64)
  1316  			}
  1317  			if v, ok := v["ttl"]; ok {
  1318  				_, v := unwrapValue(v, &lt)
  1319  				ttl, err = time.ParseDuration(v.(string))
  1320  			}
  1321  			if v, ok := v["interval"]; err == nil && ok {
  1322  				_, v := unwrapValue(v, &lt)
  1323  				sync, err = time.ParseDuration(v.(string))
  1324  			}
  1325  			if v, ok := v["timeout"]; err == nil && ok {
  1326  				_, v := unwrapValue(v, &lt)
  1327  				var to time.Duration
  1328  				if to, err = time.ParseDuration(v.(string)); err == nil {
  1329  					opts = append(opts, FetchTimeout(to))
  1330  				}
  1331  			}
  1332  			if err != nil {
  1333  				*errors = append(*errors, &configErr{tk, err.Error()})
  1334  				return
  1335  			}
  1336  
  1337  			checkDir := func() {
  1338  				if dir == _EMPTY_ {
  1339  					*errors = append(*errors, &configErr{tk, "dir has no value and needs to point to a directory"})
  1340  					return
  1341  				}
  1342  				if info, _ := os.Stat(dir); info != nil && (!info.IsDir() || info.Mode().Perm()&(1<<(uint(7))) == 0) {
  1343  					*errors = append(*errors, &configErr{tk, "dir needs to point to an accessible directory"})
  1344  					return
  1345  				}
  1346  			}
  1347  
  1348  			var res AccountResolver
  1349  			switch strings.ToUpper(dirType) {
  1350  			case "CACHE":
  1351  				checkDir()
  1352  				if sync != 0 {
  1353  					*errors = append(*errors, &configErr{tk, "CACHE does not accept sync"})
  1354  				}
  1355  				if del {
  1356  					*errors = append(*errors, &configErr{tk, "CACHE does not accept allow_delete"})
  1357  				}
  1358  				if hdel_set {
  1359  					*errors = append(*errors, &configErr{tk, "CACHE does not accept hard_delete"})
  1360  				}
  1361  				res, err = NewCacheDirAccResolver(dir, limit, ttl, opts...)
  1362  			case "FULL":
  1363  				checkDir()
  1364  				if ttl != 0 {
  1365  					*errors = append(*errors, &configErr{tk, "FULL does not accept ttl"})
  1366  				}
  1367  				if hdel_set && !del {
  1368  					*errors = append(*errors, &configErr{tk, "hard_delete has no effect without delete"})
  1369  				}
  1370  				delete := NoDelete
  1371  				if del {
  1372  					if hdel {
  1373  						delete = HardDelete
  1374  					} else {
  1375  						delete = RenameDeleted
  1376  					}
  1377  				}
  1378  				res, err = NewDirAccResolver(dir, limit, sync, delete, opts...)
  1379  			case "MEM", "MEMORY":
  1380  				res = &MemAccResolver{}
  1381  			}
  1382  			if err != nil {
  1383  				*errors = append(*errors, &configErr{tk, err.Error()})
  1384  				return
  1385  			}
  1386  			o.AccountResolver = res
  1387  		default:
  1388  			err := &configErr{tk, fmt.Sprintf("error parsing operator resolver, wrong type %T", v)}
  1389  			*errors = append(*errors, err)
  1390  			return
  1391  		}
  1392  		if o.AccountResolver == nil {
  1393  			err := &configErr{tk, "error parsing account resolver, should be MEM or " +
  1394  				" URL(\"url\") or a map containing dir and type state=[FULL|CACHE])"}
  1395  			*errors = append(*errors, err)
  1396  		}
  1397  	case "resolver_tls":
  1398  		tc, err := parseTLS(tk, true)
  1399  		if err != nil {
  1400  			*errors = append(*errors, err)
  1401  			return
  1402  		}
  1403  		tlsConfig, err := GenTLSConfig(tc)
  1404  		if err != nil {
  1405  			err := &configErr{tk, err.Error()}
  1406  			*errors = append(*errors, err)
  1407  			return
  1408  		}
  1409  		o.AccountResolverTLSConfig = tlsConfig
  1410  		// GenTLSConfig loads the CA file into ClientCAs, but since this will
  1411  		// be used as a client connection, we need to set RootCAs.
  1412  		o.AccountResolverTLSConfig.RootCAs = tlsConfig.ClientCAs
  1413  	case "resolver_preload":
  1414  		mp, ok := v.(map[string]any)
  1415  		if !ok {
  1416  			err := &configErr{tk, "preload should be a map of account_public_key:account_jwt"}
  1417  			*errors = append(*errors, err)
  1418  			return
  1419  		}
  1420  		o.resolverPreloads = make(map[string]string)
  1421  		for key, val := range mp {
  1422  			tk, val = unwrapValue(val, &lt)
  1423  			if jwtstr, ok := val.(string); !ok {
  1424  				*errors = append(*errors, &configErr{tk, "preload map value should be a string JWT"})
  1425  				continue
  1426  			} else {
  1427  				// Make sure this is a valid account JWT, that is a config error.
  1428  				// We will warn of expirations, etc later.
  1429  				if _, err := jwt.DecodeAccountClaims(jwtstr); err != nil {
  1430  					err := &configErr{tk, "invalid account JWT"}
  1431  					*errors = append(*errors, err)
  1432  					continue
  1433  				}
  1434  				o.resolverPreloads[key] = jwtstr
  1435  			}
  1436  		}
  1437  	case "resolver_pinned_accounts":
  1438  		switch v := v.(type) {
  1439  		case string:
  1440  			o.resolverPinnedAccounts = map[string]struct{}{v: {}}
  1441  		case []string:
  1442  			o.resolverPinnedAccounts = make(map[string]struct{})
  1443  			for _, mv := range v {
  1444  				o.resolverPinnedAccounts[mv] = struct{}{}
  1445  			}
  1446  		case []any:
  1447  			o.resolverPinnedAccounts = make(map[string]struct{})
  1448  			for _, mv := range v {
  1449  				tk, mv = unwrapValue(mv, &lt)
  1450  				if key, ok := mv.(string); ok {
  1451  					o.resolverPinnedAccounts[key] = struct{}{}
  1452  				} else {
  1453  					err := &configErr{tk,
  1454  						fmt.Sprintf("error parsing resolver_pinned_accounts: unsupported type in array %T", mv)}
  1455  					*errors = append(*errors, err)
  1456  					continue
  1457  				}
  1458  			}
  1459  		default:
  1460  			err := &configErr{tk, fmt.Sprintf("error parsing resolver_pinned_accounts: unsupported type %T", v)}
  1461  			*errors = append(*errors, err)
  1462  			return
  1463  		}
  1464  	case "no_auth_user":
  1465  		o.NoAuthUser = v.(string)
  1466  	case "system_account", "system":
  1467  		// Already processed at the beginning so we just skip them
  1468  		// to not treat them as unknown values.
  1469  		return
  1470  	case "no_system_account", "no_system", "no_sys_acc":
  1471  		o.NoSystemAccount = v.(bool)
  1472  	case "no_header_support":
  1473  		o.NoHeaderSupport = v.(bool)
  1474  	case "trusted", "trusted_keys":
  1475  		switch v := v.(type) {
  1476  		case string:
  1477  			o.TrustedKeys = []string{v}
  1478  		case []string:
  1479  			o.TrustedKeys = v
  1480  		case []any:
  1481  			keys := make([]string, 0, len(v))
  1482  			for _, mv := range v {
  1483  				tk, mv = unwrapValue(mv, &lt)
  1484  				if key, ok := mv.(string); ok {
  1485  					keys = append(keys, key)
  1486  				} else {
  1487  					err := &configErr{tk, fmt.Sprintf("error parsing trusted: unsupported type in array %T", mv)}
  1488  					*errors = append(*errors, err)
  1489  					continue
  1490  				}
  1491  			}
  1492  			o.TrustedKeys = keys
  1493  		default:
  1494  			err := &configErr{tk, fmt.Sprintf("error parsing trusted: unsupported type %T", v)}
  1495  			*errors = append(*errors, err)
  1496  		}
  1497  		// Do a quick sanity check on keys
  1498  		for _, key := range o.TrustedKeys {
  1499  			if !nkeys.IsValidPublicOperatorKey(key) {
  1500  				err := &configErr{tk, fmt.Sprintf("trust key %q required to be a valid public operator nkey", key)}
  1501  				*errors = append(*errors, err)
  1502  			}
  1503  		}
  1504  	case "connect_error_reports":
  1505  		o.ConnectErrorReports = int(v.(int64))
  1506  	case "reconnect_error_reports":
  1507  		o.ReconnectErrorReports = int(v.(int64))
  1508  	case "websocket", "ws":
  1509  		if err := parseWebsocket(tk, o, errors); err != nil {
  1510  			*errors = append(*errors, err)
  1511  			return
  1512  		}
  1513  	case "mqtt":
  1514  		if err := parseMQTT(tk, o, errors, warnings); err != nil {
  1515  			*errors = append(*errors, err)
  1516  			return
  1517  		}
  1518  	case "server_tags":
  1519  		var err error
  1520  		switch v := v.(type) {
  1521  		case string:
  1522  			o.Tags.Add(v)
  1523  		case []string:
  1524  			o.Tags.Add(v...)
  1525  		case []any:
  1526  			for _, t := range v {
  1527  				if token, ok := t.(token); ok {
  1528  					if ts, ok := token.Value().(string); ok {
  1529  						o.Tags.Add(ts)
  1530  						continue
  1531  					} else {
  1532  						err = &configErr{tk, fmt.Sprintf("error parsing tags: unsupported type %T where string is expected", token)}
  1533  					}
  1534  				} else {
  1535  					err = &configErr{tk, fmt.Sprintf("error parsing tags: unsupported type %T", t)}
  1536  				}
  1537  				break
  1538  			}
  1539  		default:
  1540  			err = &configErr{tk, fmt.Sprintf("error parsing tags: unsupported type %T", v)}
  1541  		}
  1542  		if err != nil {
  1543  			*errors = append(*errors, err)
  1544  			return
  1545  		}
  1546  	case "default_js_domain":
  1547  		vv, ok := v.(map[string]any)
  1548  		if !ok {
  1549  			*errors = append(*errors, &configErr{tk, fmt.Sprintf("error default_js_domain config: unsupported type %T", v)})
  1550  			return
  1551  		}
  1552  		m := make(map[string]string)
  1553  		for kk, kv := range vv {
  1554  			_, v = unwrapValue(kv, &tk)
  1555  			m[kk] = v.(string)
  1556  		}
  1557  		o.JsAccDefaultDomain = m
  1558  	case "ocsp_cache":
  1559  		var err error
  1560  		switch vv := v.(type) {
  1561  		case bool:
  1562  			pc := NewOCSPResponseCacheConfig()
  1563  			if vv {
  1564  				// Set enabled
  1565  				pc.Type = LOCAL
  1566  				o.OCSPCacheConfig = pc
  1567  			} else {
  1568  				// Set disabled (none cache)
  1569  				pc.Type = NONE
  1570  				o.OCSPCacheConfig = pc
  1571  			}
  1572  		case map[string]any:
  1573  			pc, err := parseOCSPResponseCache(v)
  1574  			if err != nil {
  1575  				*errors = append(*errors, err)
  1576  				return
  1577  			}
  1578  			o.OCSPCacheConfig = pc
  1579  		default:
  1580  			err = &configErr{tk, fmt.Sprintf("error parsing tags: unsupported type %T", v)}
  1581  		}
  1582  		if err != nil {
  1583  			*errors = append(*errors, err)
  1584  			return
  1585  		}
  1586  	default:
  1587  		if au := atomic.LoadInt32(&allowUnknownTopLevelField); au == 0 && !tk.IsUsedVariable() {
  1588  			err := &unknownConfigFieldErr{
  1589  				field: k,
  1590  				configErr: configErr{
  1591  					token: tk,
  1592  				},
  1593  			}
  1594  			*errors = append(*errors, err)
  1595  		}
  1596  	}
  1597  }
  1598  
  1599  func setupUsersAndNKeysDuplicateCheckMap(o *Options) map[string]struct{} {
  1600  	unames := make(map[string]struct{}, len(o.Users)+len(o.Nkeys))
  1601  	for _, u := range o.Users {
  1602  		unames[u.Username] = struct{}{}
  1603  	}
  1604  	for _, u := range o.Nkeys {
  1605  		unames[u.Nkey] = struct{}{}
  1606  	}
  1607  	return unames
  1608  }
  1609  
  1610  func parseDuration(field string, tk token, v any, errors *[]error, warnings *[]error) time.Duration {
  1611  	if wd, ok := v.(string); ok {
  1612  		if dur, err := time.ParseDuration(wd); err != nil {
  1613  			err := &configErr{tk, fmt.Sprintf("error parsing %s: %v", field, err)}
  1614  			*errors = append(*errors, err)
  1615  			return 0
  1616  		} else {
  1617  			return dur
  1618  		}
  1619  	} else {
  1620  		// Backward compatible with old type, assume this is the
  1621  		// number of seconds.
  1622  		err := &configWarningErr{
  1623  			field: field,
  1624  			configErr: configErr{
  1625  				token:  tk,
  1626  				reason: field + " should be converted to a duration",
  1627  			},
  1628  		}
  1629  		*warnings = append(*warnings, err)
  1630  		return time.Duration(v.(int64)) * time.Second
  1631  	}
  1632  }
  1633  
  1634  func trackExplicitVal(pm *map[string]bool, name string, val bool) {
  1635  	m := *pm
  1636  	if m == nil {
  1637  		m = make(map[string]bool)
  1638  		*pm = m
  1639  	}
  1640  	m[name] = val
  1641  }
  1642  
  1643  // hostPort is simple struct to hold parsed listen/addr strings.
  1644  type hostPort struct {
  1645  	host string
  1646  	port int
  1647  }
  1648  
  1649  // parseListen will parse listen option which is replacing host/net and port
  1650  func parseListen(v any) (*hostPort, error) {
  1651  	hp := &hostPort{}
  1652  	switch vv := v.(type) {
  1653  	// Only a port
  1654  	case int64:
  1655  		hp.port = int(vv)
  1656  	case string:
  1657  		host, port, err := net.SplitHostPort(vv)
  1658  		if err != nil {
  1659  			return nil, fmt.Errorf("could not parse address string %q", vv)
  1660  		}
  1661  		hp.port, err = strconv.Atoi(port)
  1662  		if err != nil {
  1663  			return nil, fmt.Errorf("could not parse port %q", port)
  1664  		}
  1665  		hp.host = host
  1666  	default:
  1667  		return nil, fmt.Errorf("expected port or host:port, got %T", vv)
  1668  	}
  1669  	return hp, nil
  1670  }
  1671  
  1672  // parseCluster will parse the cluster config.
  1673  func parseCluster(v any, opts *Options, errors *[]error, warnings *[]error) error {
  1674  	var lt token
  1675  	defer convertPanicToErrorList(&lt, errors)
  1676  
  1677  	tk, v := unwrapValue(v, &lt)
  1678  	cm, ok := v.(map[string]any)
  1679  	if !ok {
  1680  		return &configErr{tk, fmt.Sprintf("Expected map to define cluster, got %T", v)}
  1681  	}
  1682  
  1683  	for mk, mv := range cm {
  1684  		// Again, unwrap token value if line check is required.
  1685  		tk, mv = unwrapValue(mv, &lt)
  1686  		switch strings.ToLower(mk) {
  1687  		case "name":
  1688  			opts.Cluster.Name = mv.(string)
  1689  		case "listen":
  1690  			hp, err := parseListen(mv)
  1691  			if err != nil {
  1692  				err := &configErr{tk, err.Error()}
  1693  				*errors = append(*errors, err)
  1694  				continue
  1695  			}
  1696  			opts.Cluster.Host = hp.host
  1697  			opts.Cluster.Port = hp.port
  1698  		case "port":
  1699  			opts.Cluster.Port = int(mv.(int64))
  1700  		case "host", "net":
  1701  			opts.Cluster.Host = mv.(string)
  1702  		case "authorization":
  1703  			auth, err := parseAuthorization(tk, errors)
  1704  			if err != nil {
  1705  				*errors = append(*errors, err)
  1706  				continue
  1707  			}
  1708  			if auth.users != nil {
  1709  				err := &configErr{tk, "Cluster authorization does not allow multiple users"}
  1710  				*errors = append(*errors, err)
  1711  				continue
  1712  			}
  1713  			if auth.token != _EMPTY_ {
  1714  				err := &configErr{tk, "Cluster authorization does not support tokens"}
  1715  				*errors = append(*errors, err)
  1716  				continue
  1717  			}
  1718  			if auth.callout != nil {
  1719  				err := &configErr{tk, "Cluster authorization does not support callouts"}
  1720  				*errors = append(*errors, err)
  1721  				continue
  1722  			}
  1723  
  1724  			opts.Cluster.Username = auth.user
  1725  			opts.Cluster.Password = auth.pass
  1726  			opts.Cluster.AuthTimeout = auth.timeout
  1727  
  1728  			if auth.defaultPermissions != nil {
  1729  				err := &configWarningErr{
  1730  					field: mk,
  1731  					configErr: configErr{
  1732  						token:  tk,
  1733  						reason: `setting "permissions" within cluster authorization block is deprecated`,
  1734  					},
  1735  				}
  1736  				*warnings = append(*warnings, err)
  1737  
  1738  				// Do not set permissions if they were specified in top-level cluster block.
  1739  				if opts.Cluster.Permissions == nil {
  1740  					setClusterPermissions(&opts.Cluster, auth.defaultPermissions)
  1741  				}
  1742  			}
  1743  		case "routes":
  1744  			ra := mv.([]any)
  1745  			routes, errs := parseURLs(ra, "route", warnings)
  1746  			if errs != nil {
  1747  				*errors = append(*errors, errs...)
  1748  				continue
  1749  			}
  1750  			opts.Routes = routes
  1751  		case "tls":
  1752  			config, tlsopts, err := getTLSConfig(tk)
  1753  			if err != nil {
  1754  				*errors = append(*errors, err)
  1755  				continue
  1756  			}
  1757  			opts.Cluster.TLSConfig = config
  1758  			opts.Cluster.TLSTimeout = tlsopts.Timeout
  1759  			opts.Cluster.TLSMap = tlsopts.Map
  1760  			opts.Cluster.TLSPinnedCerts = tlsopts.PinnedCerts
  1761  			opts.Cluster.TLSCheckKnownURLs = tlsopts.TLSCheckKnownURLs
  1762  			opts.Cluster.tlsConfigOpts = tlsopts
  1763  		case "cluster_advertise", "advertise":
  1764  			opts.Cluster.Advertise = mv.(string)
  1765  		case "no_advertise":
  1766  			opts.Cluster.NoAdvertise = mv.(bool)
  1767  			trackExplicitVal(&opts.inConfig, "Cluster.NoAdvertise", opts.Cluster.NoAdvertise)
  1768  		case "connect_retries":
  1769  			opts.Cluster.ConnectRetries = int(mv.(int64))
  1770  		case "permissions":
  1771  			perms, err := parseUserPermissions(mv, errors)
  1772  			if err != nil {
  1773  				*errors = append(*errors, err)
  1774  				continue
  1775  			}
  1776  			// Dynamic response permissions do not make sense here.
  1777  			if perms.Response != nil {
  1778  				err := &configErr{tk, "Cluster permissions do not support dynamic responses"}
  1779  				*errors = append(*errors, err)
  1780  				continue
  1781  			}
  1782  			// This will possibly override permissions that were define in auth block
  1783  			setClusterPermissions(&opts.Cluster, perms)
  1784  		case "pool_size":
  1785  			opts.Cluster.PoolSize = int(mv.(int64))
  1786  		case "accounts":
  1787  			opts.Cluster.PinnedAccounts, _ = parseStringArray("accounts", tk, &lt, mv, errors)
  1788  		case "compression":
  1789  			if err := parseCompression(&opts.Cluster.Compression, CompressionS2Fast, tk, mk, mv); err != nil {
  1790  				*errors = append(*errors, err)
  1791  				continue
  1792  			}
  1793  		case "ping_interval":
  1794  			opts.Cluster.PingInterval = parseDuration("ping_interval", tk, mv, errors, warnings)
  1795  			if opts.Cluster.PingInterval > routeMaxPingInterval {
  1796  				*warnings = append(*warnings, &configErr{tk, fmt.Sprintf("Cluster 'ping_interval' will reset to %v which is the max for routes", routeMaxPingInterval)})
  1797  			}
  1798  		case "ping_max":
  1799  			opts.Cluster.MaxPingsOut = int(mv.(int64))
  1800  		default:
  1801  			if !tk.IsUsedVariable() {
  1802  				err := &unknownConfigFieldErr{
  1803  					field: mk,
  1804  					configErr: configErr{
  1805  						token: tk,
  1806  					},
  1807  				}
  1808  				*errors = append(*errors, err)
  1809  				continue
  1810  			}
  1811  		}
  1812  	}
  1813  	return nil
  1814  }
  1815  
  1816  // The parameter `chosenModeForOn` indicates which compression mode to use
  1817  // when the user selects "on" (or enabled, true, etc..). This is because
  1818  // we may have different defaults depending on where the compression is used.
  1819  func parseCompression(c *CompressionOpts, chosenModeForOn string, tk token, mk string, mv any) (retErr error) {
  1820  	var lt token
  1821  	defer convertPanicToError(&lt, &retErr)
  1822  
  1823  	switch mv := mv.(type) {
  1824  	case string:
  1825  		// Do not validate here, it will be done in NewServer.
  1826  		c.Mode = mv
  1827  	case bool:
  1828  		if mv {
  1829  			c.Mode = chosenModeForOn
  1830  		} else {
  1831  			c.Mode = CompressionOff
  1832  		}
  1833  	case map[string]any:
  1834  		for mk, mv := range mv {
  1835  			tk, mv = unwrapValue(mv, &lt)
  1836  			switch strings.ToLower(mk) {
  1837  			case "mode":
  1838  				c.Mode = mv.(string)
  1839  			case "rtt_thresholds", "thresholds", "rtts", "rtt":
  1840  				for _, iv := range mv.([]any) {
  1841  					_, mv := unwrapValue(iv, &lt)
  1842  					dur, err := time.ParseDuration(mv.(string))
  1843  					if err != nil {
  1844  						return &configErr{tk, err.Error()}
  1845  					}
  1846  					c.RTTThresholds = append(c.RTTThresholds, dur)
  1847  				}
  1848  			default:
  1849  				if !tk.IsUsedVariable() {
  1850  					return &configErr{tk, fmt.Sprintf("unknown field %q", mk)}
  1851  				}
  1852  			}
  1853  		}
  1854  	default:
  1855  		return &configErr{tk, fmt.Sprintf("field %q should be a boolean or a structure, got %T", mk, mv)}
  1856  	}
  1857  	return nil
  1858  }
  1859  
  1860  func parseURLs(a []any, typ string, warnings *[]error) (urls []*url.URL, errors []error) {
  1861  	urls = make([]*url.URL, 0, len(a))
  1862  	var lt token
  1863  	defer convertPanicToErrorList(&lt, &errors)
  1864  
  1865  	dd := make(map[string]bool)
  1866  
  1867  	for _, u := range a {
  1868  		tk, u := unwrapValue(u, &lt)
  1869  		sURL := u.(string)
  1870  		if dd[sURL] {
  1871  			err := &configWarningErr{
  1872  				field: sURL,
  1873  				configErr: configErr{
  1874  					token:  tk,
  1875  					reason: fmt.Sprintf("Duplicate %s entry detected", typ),
  1876  				},
  1877  			}
  1878  			*warnings = append(*warnings, err)
  1879  			continue
  1880  		}
  1881  		dd[sURL] = true
  1882  		url, err := parseURL(sURL, typ)
  1883  		if err != nil {
  1884  			err := &configErr{tk, err.Error()}
  1885  			errors = append(errors, err)
  1886  			continue
  1887  		}
  1888  		urls = append(urls, url)
  1889  	}
  1890  	return urls, errors
  1891  }
  1892  
  1893  func parseURL(u string, typ string) (*url.URL, error) {
  1894  	urlStr := strings.TrimSpace(u)
  1895  	url, err := url.Parse(urlStr)
  1896  	if err != nil {
  1897  		// Security note: if it's not well-formed but still reached us, then we're going to log as-is which might include password information here.
  1898  		// If the URL parses, we don't log the credentials ever, but if it doesn't even parse we don't have a sane way to redact.
  1899  		return nil, fmt.Errorf("error parsing %s url [%q]", typ, urlStr)
  1900  	}
  1901  	return url, nil
  1902  }
  1903  
  1904  func parseGateway(v any, o *Options, errors *[]error, warnings *[]error) error {
  1905  	var lt token
  1906  	defer convertPanicToErrorList(&lt, errors)
  1907  
  1908  	tk, v := unwrapValue(v, &lt)
  1909  	gm, ok := v.(map[string]any)
  1910  	if !ok {
  1911  		return &configErr{tk, fmt.Sprintf("Expected gateway to be a map, got %T", v)}
  1912  	}
  1913  	for mk, mv := range gm {
  1914  		// Again, unwrap token value if line check is required.
  1915  		tk, mv = unwrapValue(mv, &lt)
  1916  		switch strings.ToLower(mk) {
  1917  		case "name":
  1918  			o.Gateway.Name = mv.(string)
  1919  		case "listen":
  1920  			hp, err := parseListen(mv)
  1921  			if err != nil {
  1922  				err := &configErr{tk, err.Error()}
  1923  				*errors = append(*errors, err)
  1924  				continue
  1925  			}
  1926  			o.Gateway.Host = hp.host
  1927  			o.Gateway.Port = hp.port
  1928  		case "port":
  1929  			o.Gateway.Port = int(mv.(int64))
  1930  		case "host", "net":
  1931  			o.Gateway.Host = mv.(string)
  1932  		case "authorization":
  1933  			auth, err := parseAuthorization(tk, errors)
  1934  			if err != nil {
  1935  				*errors = append(*errors, err)
  1936  				continue
  1937  			}
  1938  			if auth.users != nil {
  1939  				*errors = append(*errors, &configErr{tk, "Gateway authorization does not allow multiple users"})
  1940  				continue
  1941  			}
  1942  			if auth.token != _EMPTY_ {
  1943  				err := &configErr{tk, "Gateway authorization does not support tokens"}
  1944  				*errors = append(*errors, err)
  1945  				continue
  1946  			}
  1947  			if auth.callout != nil {
  1948  				err := &configErr{tk, "Gateway authorization does not support callouts"}
  1949  				*errors = append(*errors, err)
  1950  				continue
  1951  			}
  1952  
  1953  			o.Gateway.Username = auth.user
  1954  			o.Gateway.Password = auth.pass
  1955  			o.Gateway.AuthTimeout = auth.timeout
  1956  		case "tls":
  1957  			config, tlsopts, err := getTLSConfig(tk)
  1958  			if err != nil {
  1959  				*errors = append(*errors, err)
  1960  				continue
  1961  			}
  1962  			o.Gateway.TLSConfig = config
  1963  			o.Gateway.TLSTimeout = tlsopts.Timeout
  1964  			o.Gateway.TLSMap = tlsopts.Map
  1965  			o.Gateway.TLSCheckKnownURLs = tlsopts.TLSCheckKnownURLs
  1966  			o.Gateway.TLSPinnedCerts = tlsopts.PinnedCerts
  1967  			o.Gateway.tlsConfigOpts = tlsopts
  1968  		case "advertise":
  1969  			o.Gateway.Advertise = mv.(string)
  1970  		case "connect_retries":
  1971  			o.Gateway.ConnectRetries = int(mv.(int64))
  1972  		case "gateways":
  1973  			gateways, err := parseGateways(mv, errors, warnings)
  1974  			if err != nil {
  1975  				return err
  1976  			}
  1977  			o.Gateway.Gateways = gateways
  1978  		case "reject_unknown", "reject_unknown_cluster":
  1979  			o.Gateway.RejectUnknown = mv.(bool)
  1980  		default:
  1981  			if !tk.IsUsedVariable() {
  1982  				err := &unknownConfigFieldErr{
  1983  					field: mk,
  1984  					configErr: configErr{
  1985  						token: tk,
  1986  					},
  1987  				}
  1988  				*errors = append(*errors, err)
  1989  				continue
  1990  			}
  1991  		}
  1992  	}
  1993  	return nil
  1994  }
  1995  
  1996  var dynamicJSAccountLimits = JetStreamAccountLimits{-1, -1, -1, -1, -1, -1, -1, false}
  1997  var defaultJSAccountTiers = map[string]JetStreamAccountLimits{_EMPTY_: dynamicJSAccountLimits}
  1998  
  1999  // Parses jetstream account limits for an account. Simple setup with boolen is allowed, and we will
  2000  // use dynamic account limits.
  2001  func parseJetStreamForAccount(v any, acc *Account, errors *[]error) error {
  2002  	var lt token
  2003  
  2004  	tk, v := unwrapValue(v, &lt)
  2005  
  2006  	// Value here can be bool, or string "enabled" or a map.
  2007  	switch vv := v.(type) {
  2008  	case bool:
  2009  		if vv {
  2010  			acc.jsLimits = defaultJSAccountTiers
  2011  		}
  2012  	case string:
  2013  		switch strings.ToLower(vv) {
  2014  		case "enabled", "enable":
  2015  			acc.jsLimits = defaultJSAccountTiers
  2016  		case "disabled", "disable":
  2017  			acc.jsLimits = nil
  2018  		default:
  2019  			return &configErr{tk, fmt.Sprintf("Expected 'enabled' or 'disabled' for string value, got '%s'", vv)}
  2020  		}
  2021  	case map[string]any:
  2022  		jsLimits := JetStreamAccountLimits{-1, -1, -1, -1, -1, -1, -1, false}
  2023  		for mk, mv := range vv {
  2024  			tk, mv = unwrapValue(mv, &lt)
  2025  			switch strings.ToLower(mk) {
  2026  			case "max_memory", "max_mem", "mem", "memory":
  2027  				vv, ok := mv.(int64)
  2028  				if !ok {
  2029  					return &configErr{tk, fmt.Sprintf("Expected a parseable size for %q, got %v", mk, mv)}
  2030  				}
  2031  				jsLimits.MaxMemory = vv
  2032  			case "max_store", "max_file", "max_disk", "store", "disk":
  2033  				vv, ok := mv.(int64)
  2034  				if !ok {
  2035  					return &configErr{tk, fmt.Sprintf("Expected a parseable size for %q, got %v", mk, mv)}
  2036  				}
  2037  				jsLimits.MaxStore = vv
  2038  			case "max_streams", "streams":
  2039  				vv, ok := mv.(int64)
  2040  				if !ok {
  2041  					return &configErr{tk, fmt.Sprintf("Expected a parseable size for %q, got %v", mk, mv)}
  2042  				}
  2043  				jsLimits.MaxStreams = int(vv)
  2044  			case "max_consumers", "consumers":
  2045  				vv, ok := mv.(int64)
  2046  				if !ok {
  2047  					return &configErr{tk, fmt.Sprintf("Expected a parseable size for %q, got %v", mk, mv)}
  2048  				}
  2049  				jsLimits.MaxConsumers = int(vv)
  2050  			case "max_bytes_required", "max_stream_bytes", "max_bytes":
  2051  				vv, ok := mv.(bool)
  2052  				if !ok {
  2053  					return &configErr{tk, fmt.Sprintf("Expected a parseable bool for %q, got %v", mk, mv)}
  2054  				}
  2055  				jsLimits.MaxBytesRequired = vv
  2056  			case "mem_max_stream_bytes", "memory_max_stream_bytes":
  2057  				vv, ok := mv.(int64)
  2058  				if !ok {
  2059  					return &configErr{tk, fmt.Sprintf("Expected a parseable size for %q, got %v", mk, mv)}
  2060  				}
  2061  				jsLimits.MemoryMaxStreamBytes = vv
  2062  			case "disk_max_stream_bytes", "store_max_stream_bytes":
  2063  				vv, ok := mv.(int64)
  2064  				if !ok {
  2065  					return &configErr{tk, fmt.Sprintf("Expected a parseable size for %q, got %v", mk, mv)}
  2066  				}
  2067  				jsLimits.StoreMaxStreamBytes = vv
  2068  			case "max_ack_pending":
  2069  				vv, ok := mv.(int64)
  2070  				if !ok {
  2071  					return &configErr{tk, fmt.Sprintf("Expected a parseable size for %q, got %v", mk, mv)}
  2072  				}
  2073  				jsLimits.MaxAckPending = int(vv)
  2074  			default:
  2075  				if !tk.IsUsedVariable() {
  2076  					err := &unknownConfigFieldErr{
  2077  						field: mk,
  2078  						configErr: configErr{
  2079  							token: tk,
  2080  						},
  2081  					}
  2082  					*errors = append(*errors, err)
  2083  					continue
  2084  				}
  2085  			}
  2086  		}
  2087  		acc.jsLimits = map[string]JetStreamAccountLimits{_EMPTY_: jsLimits}
  2088  	default:
  2089  		return &configErr{tk, fmt.Sprintf("Expected map, bool or string to define JetStream, got %T", v)}
  2090  	}
  2091  	return nil
  2092  }
  2093  
  2094  // takes in a storage size as either an int or a string and returns an int64 value based on the input.
  2095  func getStorageSize(v any) (int64, error) {
  2096  	_, ok := v.(int64)
  2097  	if ok {
  2098  		return v.(int64), nil
  2099  	}
  2100  
  2101  	s, ok := v.(string)
  2102  	if !ok {
  2103  		return 0, fmt.Errorf("must be int64 or string")
  2104  	}
  2105  
  2106  	if s == _EMPTY_ {
  2107  		return 0, nil
  2108  	}
  2109  
  2110  	suffix := s[len(s)-1:]
  2111  	prefix := s[:len(s)-1]
  2112  	num, err := strconv.ParseInt(prefix, 10, 64)
  2113  	if err != nil {
  2114  		return 0, err
  2115  	}
  2116  
  2117  	suffixMap := map[string]int64{"K": 10, "M": 20, "G": 30, "T": 40}
  2118  
  2119  	mult, ok := suffixMap[suffix]
  2120  	if !ok {
  2121  		return 0, fmt.Errorf("sizes defined as strings must end in K, M, G, T")
  2122  	}
  2123  	num *= 1 << mult
  2124  
  2125  	return num, nil
  2126  }
  2127  
  2128  // Parse enablement of jetstream for a server.
  2129  func parseJetStreamLimits(v any, opts *Options, errors *[]error) error {
  2130  	var lt token
  2131  	tk, v := unwrapValue(v, &lt)
  2132  
  2133  	lim := JSLimitOpts{}
  2134  
  2135  	vv, ok := v.(map[string]any)
  2136  	if !ok {
  2137  		return &configErr{tk, fmt.Sprintf("Expected a map to define JetStreamLimits, got %T", v)}
  2138  	}
  2139  	for mk, mv := range vv {
  2140  		tk, mv = unwrapValue(mv, &lt)
  2141  		switch strings.ToLower(mk) {
  2142  		case "max_ack_pending":
  2143  			lim.MaxAckPending = int(mv.(int64))
  2144  		case "max_ha_assets":
  2145  			lim.MaxHAAssets = int(mv.(int64))
  2146  		case "max_request_batch":
  2147  			lim.MaxRequestBatch = int(mv.(int64))
  2148  		case "duplicate_window":
  2149  			var err error
  2150  			lim.Duplicates, err = time.ParseDuration(mv.(string))
  2151  			if err != nil {
  2152  				*errors = append(*errors, err)
  2153  			}
  2154  		default:
  2155  			if !tk.IsUsedVariable() {
  2156  				err := &unknownConfigFieldErr{
  2157  					field: mk,
  2158  					configErr: configErr{
  2159  						token: tk,
  2160  					},
  2161  				}
  2162  				*errors = append(*errors, err)
  2163  				continue
  2164  			}
  2165  		}
  2166  	}
  2167  	opts.JetStreamLimits = lim
  2168  	return nil
  2169  }
  2170  
  2171  // Parse the JetStream TPM options.
  2172  func parseJetStreamTPM(v interface{}, opts *Options, errors *[]error) error {
  2173  	var lt token
  2174  	tk, v := unwrapValue(v, &lt)
  2175  
  2176  	tpm := JSTpmOpts{}
  2177  
  2178  	vv, ok := v.(map[string]interface{})
  2179  	if !ok {
  2180  		return &configErr{tk, fmt.Sprintf("Expected a map to define JetStreamLimits, got %T", v)}
  2181  	}
  2182  	for mk, mv := range vv {
  2183  		tk, mv = unwrapValue(mv, &lt)
  2184  		switch strings.ToLower(mk) {
  2185  		case "keys_file":
  2186  			tpm.KeysFile = mv.(string)
  2187  		case "encryption_password":
  2188  			tpm.KeyPassword = mv.(string)
  2189  		case "srk_password":
  2190  			tpm.SrkPassword = mv.(string)
  2191  		case "pcr":
  2192  			tpm.Pcr = int(mv.(int64))
  2193  		case "cipher":
  2194  			if err := setJetStreamEkCipher(opts, mv, tk); err != nil {
  2195  				return err
  2196  			}
  2197  		default:
  2198  			if !tk.IsUsedVariable() {
  2199  				err := &unknownConfigFieldErr{
  2200  					field: mk,
  2201  					configErr: configErr{
  2202  						token: tk,
  2203  					},
  2204  				}
  2205  				*errors = append(*errors, err)
  2206  				continue
  2207  			}
  2208  		}
  2209  	}
  2210  	opts.JetStreamTpm = tpm
  2211  	return nil
  2212  }
  2213  
  2214  func setJetStreamEkCipher(opts *Options, mv interface{}, tk token) error {
  2215  	switch strings.ToLower(mv.(string)) {
  2216  	case "chacha", "chachapoly":
  2217  		opts.JetStreamCipher = ChaCha
  2218  	case "aes":
  2219  		opts.JetStreamCipher = AES
  2220  	default:
  2221  		return &configErr{tk, fmt.Sprintf("Unknown cipher type: %q", mv)}
  2222  	}
  2223  	return nil
  2224  }
  2225  
  2226  // Parse enablement of jetstream for a server.
  2227  func parseJetStream(v any, opts *Options, errors *[]error, warnings *[]error) error {
  2228  	var lt token
  2229  
  2230  	tk, v := unwrapValue(v, &lt)
  2231  
  2232  	// Value here can be bool, or string "enabled" or a map.
  2233  	switch vv := v.(type) {
  2234  	case bool:
  2235  		opts.JetStream = v.(bool)
  2236  	case string:
  2237  		switch strings.ToLower(vv) {
  2238  		case "enabled", "enable":
  2239  			opts.JetStream = true
  2240  		case "disabled", "disable":
  2241  			opts.JetStream = false
  2242  		default:
  2243  			return &configErr{tk, fmt.Sprintf("Expected 'enabled' or 'disabled' for string value, got '%s'", vv)}
  2244  		}
  2245  	case map[string]any:
  2246  		doEnable := true
  2247  		for mk, mv := range vv {
  2248  			tk, mv = unwrapValue(mv, &lt)
  2249  			switch strings.ToLower(mk) {
  2250  			case "store", "store_dir", "storedir":
  2251  				// StoreDir can be set at the top level as well so have to prevent ambiguous declarations.
  2252  				if opts.StoreDir != _EMPTY_ {
  2253  					return &configErr{tk, "Duplicate 'store_dir' configuration"}
  2254  				}
  2255  				opts.StoreDir = mv.(string)
  2256  			case "sync", "sync_interval":
  2257  				if v, ok := mv.(string); ok && strings.ToLower(v) == "always" {
  2258  					opts.SyncInterval = defaultSyncInterval
  2259  					opts.SyncAlways = true
  2260  				} else {
  2261  					opts.SyncInterval = parseDuration(mk, tk, mv, errors, warnings)
  2262  				}
  2263  				opts.syncSet = true
  2264  			case "max_memory_store", "max_mem_store", "max_mem":
  2265  				s, err := getStorageSize(mv)
  2266  				if err != nil {
  2267  					return &configErr{tk, fmt.Sprintf("max_mem_store %s", err)}
  2268  				}
  2269  				opts.JetStreamMaxMemory = s
  2270  				opts.maxMemSet = true
  2271  			case "max_file_store", "max_file":
  2272  				s, err := getStorageSize(mv)
  2273  				if err != nil {
  2274  					return &configErr{tk, fmt.Sprintf("max_file_store %s", err)}
  2275  				}
  2276  				opts.JetStreamMaxStore = s
  2277  				opts.maxStoreSet = true
  2278  			case "domain":
  2279  				opts.JetStreamDomain = mv.(string)
  2280  			case "enable", "enabled":
  2281  				doEnable = mv.(bool)
  2282  			case "key", "ek", "encryption_key":
  2283  				opts.JetStreamKey = mv.(string)
  2284  			case "prev_key", "prev_ek", "prev_encryption_key":
  2285  				opts.JetStreamOldKey = mv.(string)
  2286  			case "cipher":
  2287  				if err := setJetStreamEkCipher(opts, mv, tk); err != nil {
  2288  					return err
  2289  				}
  2290  			case "extension_hint":
  2291  				opts.JetStreamExtHint = mv.(string)
  2292  			case "limits":
  2293  				if err := parseJetStreamLimits(tk, opts, errors); err != nil {
  2294  					return err
  2295  				}
  2296  			case "tpm":
  2297  				if err := parseJetStreamTPM(tk, opts, errors); err != nil {
  2298  					return err
  2299  				}
  2300  			case "unique_tag":
  2301  				opts.JetStreamUniqueTag = strings.ToLower(strings.TrimSpace(mv.(string)))
  2302  			case "max_outstanding_catchup":
  2303  				s, err := getStorageSize(mv)
  2304  				if err != nil {
  2305  					return &configErr{tk, fmt.Sprintf("%s %s", strings.ToLower(mk), err)}
  2306  				}
  2307  				opts.JetStreamMaxCatchup = s
  2308  			default:
  2309  				if !tk.IsUsedVariable() {
  2310  					err := &unknownConfigFieldErr{
  2311  						field: mk,
  2312  						configErr: configErr{
  2313  							token: tk,
  2314  						},
  2315  					}
  2316  					*errors = append(*errors, err)
  2317  					continue
  2318  				}
  2319  			}
  2320  		}
  2321  		opts.JetStream = doEnable
  2322  	default:
  2323  		return &configErr{tk, fmt.Sprintf("Expected map, bool or string to define JetStream, got %T", v)}
  2324  	}
  2325  
  2326  	return nil
  2327  }
  2328  
  2329  // parseLeafNodes will parse the leaf node config.
  2330  func parseLeafNodes(v any, opts *Options, errors *[]error, warnings *[]error) error {
  2331  	var lt token
  2332  	defer convertPanicToErrorList(&lt, errors)
  2333  
  2334  	tk, v := unwrapValue(v, &lt)
  2335  	cm, ok := v.(map[string]any)
  2336  	if !ok {
  2337  		return &configErr{tk, fmt.Sprintf("Expected map to define a leafnode, got %T", v)}
  2338  	}
  2339  
  2340  	for mk, mv := range cm {
  2341  		// Again, unwrap token value if line check is required.
  2342  		tk, mv = unwrapValue(mv, &lt)
  2343  		switch strings.ToLower(mk) {
  2344  		case "listen":
  2345  			hp, err := parseListen(mv)
  2346  			if err != nil {
  2347  				err := &configErr{tk, err.Error()}
  2348  				*errors = append(*errors, err)
  2349  				continue
  2350  			}
  2351  			opts.LeafNode.Host = hp.host
  2352  			opts.LeafNode.Port = hp.port
  2353  		case "port":
  2354  			opts.LeafNode.Port = int(mv.(int64))
  2355  		case "host", "net":
  2356  			opts.LeafNode.Host = mv.(string)
  2357  		case "authorization":
  2358  			auth, err := parseLeafAuthorization(tk, errors)
  2359  			if err != nil {
  2360  				*errors = append(*errors, err)
  2361  				continue
  2362  			}
  2363  			opts.LeafNode.Username = auth.user
  2364  			opts.LeafNode.Password = auth.pass
  2365  			opts.LeafNode.AuthTimeout = auth.timeout
  2366  			opts.LeafNode.Account = auth.acc
  2367  			opts.LeafNode.Users = auth.users
  2368  			opts.LeafNode.Nkey = auth.nkey
  2369  			// Validate user info config for leafnode authorization
  2370  			if err := validateLeafNodeAuthOptions(opts); err != nil {
  2371  				*errors = append(*errors, &configErr{tk, err.Error()})
  2372  				continue
  2373  			}
  2374  		case "remotes":
  2375  			// Parse the remote options here.
  2376  			remotes, err := parseRemoteLeafNodes(tk, errors, warnings)
  2377  			if err != nil {
  2378  				*errors = append(*errors, err)
  2379  				continue
  2380  			}
  2381  			opts.LeafNode.Remotes = remotes
  2382  		case "reconnect", "reconnect_delay", "reconnect_interval":
  2383  			opts.LeafNode.ReconnectInterval = parseDuration("reconnect", tk, mv, errors, warnings)
  2384  		case "tls":
  2385  			tc, err := parseTLS(tk, true)
  2386  			if err != nil {
  2387  				*errors = append(*errors, err)
  2388  				continue
  2389  			}
  2390  			if opts.LeafNode.TLSConfig, err = GenTLSConfig(tc); err != nil {
  2391  				err := &configErr{tk, err.Error()}
  2392  				*errors = append(*errors, err)
  2393  				continue
  2394  			}
  2395  			opts.LeafNode.TLSTimeout = tc.Timeout
  2396  			opts.LeafNode.TLSMap = tc.Map
  2397  			opts.LeafNode.TLSPinnedCerts = tc.PinnedCerts
  2398  			opts.LeafNode.TLSHandshakeFirst = tc.HandshakeFirst
  2399  			opts.LeafNode.tlsConfigOpts = tc
  2400  		case "leafnode_advertise", "advertise":
  2401  			opts.LeafNode.Advertise = mv.(string)
  2402  		case "no_advertise":
  2403  			opts.LeafNode.NoAdvertise = mv.(bool)
  2404  			trackExplicitVal(&opts.inConfig, "LeafNode.NoAdvertise", opts.LeafNode.NoAdvertise)
  2405  		case "min_version", "minimum_version":
  2406  			version := mv.(string)
  2407  			if err := checkLeafMinVersionConfig(version); err != nil {
  2408  				err = &configErr{tk, err.Error()}
  2409  				*errors = append(*errors, err)
  2410  				continue
  2411  			}
  2412  			opts.LeafNode.MinVersion = version
  2413  		case "compression":
  2414  			if err := parseCompression(&opts.LeafNode.Compression, CompressionS2Auto, tk, mk, mv); err != nil {
  2415  				*errors = append(*errors, err)
  2416  				continue
  2417  			}
  2418  		default:
  2419  			if !tk.IsUsedVariable() {
  2420  				err := &unknownConfigFieldErr{
  2421  					field: mk,
  2422  					configErr: configErr{
  2423  						token: tk,
  2424  					},
  2425  				}
  2426  				*errors = append(*errors, err)
  2427  				continue
  2428  			}
  2429  		}
  2430  	}
  2431  	return nil
  2432  }
  2433  
  2434  // This is the authorization parser adapter for the leafnode's
  2435  // authorization config.
  2436  func parseLeafAuthorization(v any, errors *[]error) (*authorization, error) {
  2437  	var (
  2438  		am   map[string]any
  2439  		tk   token
  2440  		lt   token
  2441  		auth = &authorization{}
  2442  	)
  2443  	defer convertPanicToErrorList(&lt, errors)
  2444  
  2445  	_, v = unwrapValue(v, &lt)
  2446  	am = v.(map[string]any)
  2447  	for mk, mv := range am {
  2448  		tk, mv = unwrapValue(mv, &lt)
  2449  		switch strings.ToLower(mk) {
  2450  		case "user", "username":
  2451  			auth.user = mv.(string)
  2452  		case "pass", "password":
  2453  			auth.pass = mv.(string)
  2454  		case "nkey":
  2455  			nk := mv.(string)
  2456  			if !nkeys.IsValidPublicUserKey(nk) {
  2457  				*errors = append(*errors, &configErr{tk, "Not a valid public nkey for leafnode authorization"})
  2458  			}
  2459  			auth.nkey = nk
  2460  		case "timeout":
  2461  			at := float64(1)
  2462  			switch mv := mv.(type) {
  2463  			case int64:
  2464  				at = float64(mv)
  2465  			case float64:
  2466  				at = mv
  2467  			}
  2468  			auth.timeout = at
  2469  		case "users":
  2470  			users, err := parseLeafUsers(tk, errors)
  2471  			if err != nil {
  2472  				*errors = append(*errors, err)
  2473  				continue
  2474  			}
  2475  			auth.users = users
  2476  		case "account":
  2477  			auth.acc = mv.(string)
  2478  		default:
  2479  			if !tk.IsUsedVariable() {
  2480  				err := &unknownConfigFieldErr{
  2481  					field: mk,
  2482  					configErr: configErr{
  2483  						token: tk,
  2484  					},
  2485  				}
  2486  				*errors = append(*errors, err)
  2487  			}
  2488  			continue
  2489  		}
  2490  	}
  2491  	return auth, nil
  2492  }
  2493  
  2494  // This is a trimmed down version of parseUsers that is adapted
  2495  // for the users possibly defined in the authorization{} section
  2496  // of leafnodes {}.
  2497  func parseLeafUsers(mv any, errors *[]error) ([]*User, error) {
  2498  	var (
  2499  		tk    token
  2500  		lt    token
  2501  		users = []*User{}
  2502  	)
  2503  	defer convertPanicToErrorList(&lt, errors)
  2504  
  2505  	tk, mv = unwrapValue(mv, &lt)
  2506  	// Make sure we have an array
  2507  	uv, ok := mv.([]any)
  2508  	if !ok {
  2509  		return nil, &configErr{tk, fmt.Sprintf("Expected users field to be an array, got %v", mv)}
  2510  	}
  2511  	for _, u := range uv {
  2512  		tk, u = unwrapValue(u, &lt)
  2513  		// Check its a map/struct
  2514  		um, ok := u.(map[string]any)
  2515  		if !ok {
  2516  			err := &configErr{tk, fmt.Sprintf("Expected user entry to be a map/struct, got %v", u)}
  2517  			*errors = append(*errors, err)
  2518  			continue
  2519  		}
  2520  		user := &User{}
  2521  		for k, v := range um {
  2522  			tk, v = unwrapValue(v, &lt)
  2523  			switch strings.ToLower(k) {
  2524  			case "user", "username":
  2525  				user.Username = v.(string)
  2526  			case "pass", "password":
  2527  				user.Password = v.(string)
  2528  			case "account":
  2529  				// We really want to save just the account name here, but
  2530  				// the User object is *Account. So we create an account object
  2531  				// but it won't be registered anywhere. The server will just
  2532  				// use opts.LeafNode.Users[].Account.Name. Alternatively
  2533  				// we need to create internal objects to store u/p and account
  2534  				// name and have a server structure to hold that.
  2535  				user.Account = NewAccount(v.(string))
  2536  			default:
  2537  				if !tk.IsUsedVariable() {
  2538  					err := &unknownConfigFieldErr{
  2539  						field: k,
  2540  						configErr: configErr{
  2541  							token: tk,
  2542  						},
  2543  					}
  2544  					*errors = append(*errors, err)
  2545  					continue
  2546  				}
  2547  			}
  2548  		}
  2549  		users = append(users, user)
  2550  	}
  2551  	return users, nil
  2552  }
  2553  
  2554  func parseRemoteLeafNodes(v any, errors *[]error, warnings *[]error) ([]*RemoteLeafOpts, error) {
  2555  	var lt token
  2556  	defer convertPanicToErrorList(&lt, errors)
  2557  	tk, v := unwrapValue(v, &lt)
  2558  	ra, ok := v.([]any)
  2559  	if !ok {
  2560  		return nil, &configErr{tk, fmt.Sprintf("Expected remotes field to be an array, got %T", v)}
  2561  	}
  2562  	remotes := make([]*RemoteLeafOpts, 0, len(ra))
  2563  	for _, r := range ra {
  2564  		tk, r = unwrapValue(r, &lt)
  2565  		// Check its a map/struct
  2566  		rm, ok := r.(map[string]any)
  2567  		if !ok {
  2568  			*errors = append(*errors, &configErr{tk, fmt.Sprintf("Expected remote leafnode entry to be a map/struct, got %v", r)})
  2569  			continue
  2570  		}
  2571  		remote := &RemoteLeafOpts{}
  2572  		for k, v := range rm {
  2573  			tk, v = unwrapValue(v, &lt)
  2574  			switch strings.ToLower(k) {
  2575  			case "no_randomize", "dont_randomize":
  2576  				remote.NoRandomize = v.(bool)
  2577  			case "url", "urls":
  2578  				switch v := v.(type) {
  2579  				case []any, []string:
  2580  					urls, errs := parseURLs(v.([]any), "leafnode", warnings)
  2581  					if errs != nil {
  2582  						*errors = append(*errors, errs...)
  2583  						continue
  2584  					}
  2585  					remote.URLs = urls
  2586  				case string:
  2587  					url, err := parseURL(v, "leafnode")
  2588  					if err != nil {
  2589  						*errors = append(*errors, &configErr{tk, err.Error()})
  2590  						continue
  2591  					}
  2592  					remote.URLs = append(remote.URLs, url)
  2593  				default:
  2594  					*errors = append(*errors, &configErr{tk, fmt.Sprintf("Expected remote leafnode url to be an array or string, got %v", v)})
  2595  					continue
  2596  				}
  2597  			case "account", "local":
  2598  				remote.LocalAccount = v.(string)
  2599  			case "creds", "credentials":
  2600  				p, err := expandPath(v.(string))
  2601  				if err != nil {
  2602  					*errors = append(*errors, &configErr{tk, err.Error()})
  2603  					continue
  2604  				}
  2605  				// Can't have both creds and nkey
  2606  				if remote.Nkey != _EMPTY_ {
  2607  					*errors = append(*errors, &configErr{tk, "Remote leafnode can not have both creds and nkey defined"})
  2608  					continue
  2609  				}
  2610  				remote.Credentials = p
  2611  			case "nkey", "seed":
  2612  				nk := v.(string)
  2613  				if pb, _, err := nkeys.DecodeSeed([]byte(nk)); err != nil || pb != nkeys.PrefixByteUser {
  2614  					err := &configErr{tk, fmt.Sprintf("Remote leafnode nkey is not a valid seed: %q", v)}
  2615  					*errors = append(*errors, err)
  2616  					continue
  2617  				}
  2618  				if remote.Credentials != _EMPTY_ {
  2619  					*errors = append(*errors, &configErr{tk, "Remote leafnode can not have both creds and nkey defined"})
  2620  					continue
  2621  				}
  2622  				remote.Nkey = nk
  2623  			case "tls":
  2624  				tc, err := parseTLS(tk, true)
  2625  				if err != nil {
  2626  					*errors = append(*errors, err)
  2627  					continue
  2628  				}
  2629  				if remote.TLSConfig, err = GenTLSConfig(tc); err != nil {
  2630  					*errors = append(*errors, &configErr{tk, err.Error()})
  2631  					continue
  2632  				}
  2633  				// If ca_file is defined, GenTLSConfig() sets TLSConfig.ClientCAs.
  2634  				// Set RootCAs since this tls.Config is used when soliciting
  2635  				// a connection (therefore behaves as a client).
  2636  				remote.TLSConfig.RootCAs = remote.TLSConfig.ClientCAs
  2637  				if tc.Timeout > 0 {
  2638  					remote.TLSTimeout = tc.Timeout
  2639  				} else {
  2640  					remote.TLSTimeout = float64(DEFAULT_LEAF_TLS_TIMEOUT) / float64(time.Second)
  2641  				}
  2642  				remote.TLSHandshakeFirst = tc.HandshakeFirst
  2643  				remote.tlsConfigOpts = tc
  2644  			case "hub":
  2645  				remote.Hub = v.(bool)
  2646  			case "deny_imports", "deny_import":
  2647  				subjects, err := parsePermSubjects(tk, errors)
  2648  				if err != nil {
  2649  					*errors = append(*errors, err)
  2650  					continue
  2651  				}
  2652  				remote.DenyImports = subjects
  2653  			case "deny_exports", "deny_export":
  2654  				subjects, err := parsePermSubjects(tk, errors)
  2655  				if err != nil {
  2656  					*errors = append(*errors, err)
  2657  					continue
  2658  				}
  2659  				remote.DenyExports = subjects
  2660  			case "ws_compress", "ws_compression", "websocket_compress", "websocket_compression":
  2661  				remote.Websocket.Compression = v.(bool)
  2662  			case "ws_no_masking", "websocket_no_masking":
  2663  				remote.Websocket.NoMasking = v.(bool)
  2664  			case "jetstream_cluster_migrate", "js_cluster_migrate":
  2665  				remote.JetStreamClusterMigrate = true
  2666  			case "compression":
  2667  				if err := parseCompression(&remote.Compression, CompressionS2Auto, tk, k, v); err != nil {
  2668  					*errors = append(*errors, err)
  2669  					continue
  2670  				}
  2671  			default:
  2672  				if !tk.IsUsedVariable() {
  2673  					err := &unknownConfigFieldErr{
  2674  						field: k,
  2675  						configErr: configErr{
  2676  							token: tk,
  2677  						},
  2678  					}
  2679  					*errors = append(*errors, err)
  2680  					continue
  2681  				}
  2682  			}
  2683  		}
  2684  		remotes = append(remotes, remote)
  2685  	}
  2686  	return remotes, nil
  2687  }
  2688  
  2689  // Parse TLS and returns a TLSConfig and TLSTimeout.
  2690  // Used by cluster and gateway parsing.
  2691  func getTLSConfig(tk token) (*tls.Config, *TLSConfigOpts, error) {
  2692  	tc, err := parseTLS(tk, false)
  2693  	if err != nil {
  2694  		return nil, nil, err
  2695  	}
  2696  	config, err := GenTLSConfig(tc)
  2697  	if err != nil {
  2698  		err := &configErr{tk, err.Error()}
  2699  		return nil, nil, err
  2700  	}
  2701  	// For clusters/gateways, we will force strict verification. We also act
  2702  	// as both client and server, so will mirror the rootCA to the
  2703  	// clientCA pool.
  2704  	config.ClientAuth = tls.RequireAndVerifyClientCert
  2705  	config.RootCAs = config.ClientCAs
  2706  	return config, tc, nil
  2707  }
  2708  
  2709  func parseGateways(v any, errors *[]error, warnings *[]error) ([]*RemoteGatewayOpts, error) {
  2710  	var lt token
  2711  	defer convertPanicToErrorList(&lt, errors)
  2712  
  2713  	tk, v := unwrapValue(v, &lt)
  2714  	// Make sure we have an array
  2715  	ga, ok := v.([]any)
  2716  	if !ok {
  2717  		return nil, &configErr{tk, fmt.Sprintf("Expected gateways field to be an array, got %T", v)}
  2718  	}
  2719  	gateways := []*RemoteGatewayOpts{}
  2720  	for _, g := range ga {
  2721  		tk, g = unwrapValue(g, &lt)
  2722  		// Check its a map/struct
  2723  		gm, ok := g.(map[string]any)
  2724  		if !ok {
  2725  			*errors = append(*errors, &configErr{tk, fmt.Sprintf("Expected gateway entry to be a map/struct, got %v", g)})
  2726  			continue
  2727  		}
  2728  		gateway := &RemoteGatewayOpts{}
  2729  		for k, v := range gm {
  2730  			tk, v = unwrapValue(v, &lt)
  2731  			switch strings.ToLower(k) {
  2732  			case "name":
  2733  				gateway.Name = v.(string)
  2734  			case "tls":
  2735  				tls, tlsopts, err := getTLSConfig(tk)
  2736  				if err != nil {
  2737  					*errors = append(*errors, err)
  2738  					continue
  2739  				}
  2740  				gateway.TLSConfig = tls
  2741  				gateway.TLSTimeout = tlsopts.Timeout
  2742  				gateway.tlsConfigOpts = tlsopts
  2743  			case "url":
  2744  				url, err := parseURL(v.(string), "gateway")
  2745  				if err != nil {
  2746  					*errors = append(*errors, &configErr{tk, err.Error()})
  2747  					continue
  2748  				}
  2749  				gateway.URLs = append(gateway.URLs, url)
  2750  			case "urls":
  2751  				urls, errs := parseURLs(v.([]any), "gateway", warnings)
  2752  				if errs != nil {
  2753  					*errors = append(*errors, errs...)
  2754  					continue
  2755  				}
  2756  				gateway.URLs = urls
  2757  			default:
  2758  				if !tk.IsUsedVariable() {
  2759  					err := &unknownConfigFieldErr{
  2760  						field: k,
  2761  						configErr: configErr{
  2762  							token: tk,
  2763  						},
  2764  					}
  2765  					*errors = append(*errors, err)
  2766  					continue
  2767  				}
  2768  			}
  2769  		}
  2770  		gateways = append(gateways, gateway)
  2771  	}
  2772  	return gateways, nil
  2773  }
  2774  
  2775  // Sets cluster's permissions based on given pub/sub permissions,
  2776  // doing the appropriate translation.
  2777  func setClusterPermissions(opts *ClusterOpts, perms *Permissions) {
  2778  	// Import is whether or not we will send a SUB for interest to the other side.
  2779  	// Export is whether or not we will accept a SUB from the remote for a given subject.
  2780  	// Both only effect interest registration.
  2781  	// The parsing sets Import into Publish and Export into Subscribe, convert
  2782  	// accordingly.
  2783  	opts.Permissions = &RoutePermissions{
  2784  		Import: perms.Publish,
  2785  		Export: perms.Subscribe,
  2786  	}
  2787  }
  2788  
  2789  // Temp structures to hold account import and export defintions since they need
  2790  // to be processed after being parsed.
  2791  type export struct {
  2792  	acc  *Account
  2793  	sub  string
  2794  	accs []string
  2795  	rt   ServiceRespType
  2796  	lat  *serviceLatency
  2797  	rthr time.Duration
  2798  	tPos uint
  2799  	atrc bool // allow_trace
  2800  }
  2801  
  2802  type importStream struct {
  2803  	acc  *Account
  2804  	an   string
  2805  	sub  string
  2806  	to   string
  2807  	pre  string
  2808  	atrc bool // allow_trace
  2809  }
  2810  
  2811  type importService struct {
  2812  	acc   *Account
  2813  	an    string
  2814  	sub   string
  2815  	to    string
  2816  	share bool
  2817  }
  2818  
  2819  // Checks if an account name is reserved.
  2820  func isReservedAccount(name string) bool {
  2821  	return name == globalAccountName
  2822  }
  2823  
  2824  func parseAccountMapDest(v any, tk token, errors *[]error) (*MapDest, *configErr) {
  2825  	// These should be maps.
  2826  	mv, ok := v.(map[string]any)
  2827  	if !ok {
  2828  		err := &configErr{tk, "Expected an entry for the mapping destination"}
  2829  		*errors = append(*errors, err)
  2830  		return nil, err
  2831  	}
  2832  
  2833  	mdest := &MapDest{}
  2834  	var lt token
  2835  	var sw bool
  2836  
  2837  	for k, v := range mv {
  2838  		tk, dmv := unwrapValue(v, &lt)
  2839  		switch strings.ToLower(k) {
  2840  		case "dest", "destination":
  2841  			mdest.Subject = dmv.(string)
  2842  		case "weight":
  2843  			switch vv := dmv.(type) {
  2844  			case string:
  2845  				ws := vv
  2846  				ws = strings.TrimSuffix(ws, "%")
  2847  				weight, err := strconv.Atoi(ws)
  2848  				if err != nil {
  2849  					err := &configErr{tk, fmt.Sprintf("Invalid weight %q for mapping destination", ws)}
  2850  					*errors = append(*errors, err)
  2851  					return nil, err
  2852  				}
  2853  				if weight > 100 || weight < 0 {
  2854  					err := &configErr{tk, fmt.Sprintf("Invalid weight %d for mapping destination", weight)}
  2855  					*errors = append(*errors, err)
  2856  					return nil, err
  2857  				}
  2858  				mdest.Weight = uint8(weight)
  2859  				sw = true
  2860  			case int64:
  2861  				weight := vv
  2862  				if weight > 100 || weight < 0 {
  2863  					err := &configErr{tk, fmt.Sprintf("Invalid weight %d for mapping destination", weight)}
  2864  					*errors = append(*errors, err)
  2865  					return nil, err
  2866  				}
  2867  				mdest.Weight = uint8(weight)
  2868  				sw = true
  2869  			default:
  2870  				err := &configErr{tk, fmt.Sprintf("Unknown entry type for weight of %v\n", vv)}
  2871  				*errors = append(*errors, err)
  2872  				return nil, err
  2873  			}
  2874  		case "cluster":
  2875  			mdest.Cluster = dmv.(string)
  2876  		default:
  2877  			err := &configErr{tk, fmt.Sprintf("Unknown field %q for mapping destination", k)}
  2878  			*errors = append(*errors, err)
  2879  			return nil, err
  2880  		}
  2881  	}
  2882  
  2883  	if !sw {
  2884  		err := &configErr{tk, fmt.Sprintf("Missing weight for mapping destination %q", mdest.Subject)}
  2885  		*errors = append(*errors, err)
  2886  		return nil, err
  2887  	}
  2888  
  2889  	return mdest, nil
  2890  }
  2891  
  2892  // parseAccountMappings is called to parse account mappings.
  2893  func parseAccountMappings(v any, acc *Account, errors *[]error) error {
  2894  	var lt token
  2895  	defer convertPanicToErrorList(&lt, errors)
  2896  
  2897  	tk, v := unwrapValue(v, &lt)
  2898  	am := v.(map[string]any)
  2899  	for subj, mv := range am {
  2900  		if !IsValidSubject(subj) {
  2901  			err := &configErr{tk, fmt.Sprintf("Subject %q is not a valid subject", subj)}
  2902  			*errors = append(*errors, err)
  2903  			continue
  2904  		}
  2905  		tk, v := unwrapValue(mv, &lt)
  2906  
  2907  		switch vv := v.(type) {
  2908  		case string:
  2909  			if err := acc.AddMapping(subj, v.(string)); err != nil {
  2910  				err := &configErr{tk, fmt.Sprintf("Error adding mapping for %q to %q : %v", subj, v.(string), err)}
  2911  				*errors = append(*errors, err)
  2912  				continue
  2913  			}
  2914  		case []any:
  2915  			var mappings []*MapDest
  2916  			for _, mv := range v.([]any) {
  2917  				tk, amv := unwrapValue(mv, &lt)
  2918  				mdest, err := parseAccountMapDest(amv, tk, errors)
  2919  				if err != nil {
  2920  					continue
  2921  				}
  2922  				mappings = append(mappings, mdest)
  2923  			}
  2924  
  2925  			// Now add them in..
  2926  			if err := acc.AddWeightedMappings(subj, mappings...); err != nil {
  2927  				err := &configErr{tk, fmt.Sprintf("Error adding mapping for %q : %v", subj, err)}
  2928  				*errors = append(*errors, err)
  2929  				continue
  2930  			}
  2931  		case any:
  2932  			tk, amv := unwrapValue(mv, &lt)
  2933  			mdest, err := parseAccountMapDest(amv, tk, errors)
  2934  			if err != nil {
  2935  				continue
  2936  			}
  2937  			// Now add it in..
  2938  			if err := acc.AddWeightedMappings(subj, mdest); err != nil {
  2939  				err := &configErr{tk, fmt.Sprintf("Error adding mapping for %q : %v", subj, err)}
  2940  				*errors = append(*errors, err)
  2941  				continue
  2942  			}
  2943  		default:
  2944  			err := &configErr{tk, fmt.Sprintf("Unknown type %T for mapping destination", vv)}
  2945  			*errors = append(*errors, err)
  2946  			continue
  2947  		}
  2948  	}
  2949  
  2950  	return nil
  2951  }
  2952  
  2953  // parseAccountLimits is called to parse account limits in a server config.
  2954  func parseAccountLimits(mv any, acc *Account, errors *[]error) error {
  2955  	var lt token
  2956  	defer convertPanicToErrorList(&lt, errors)
  2957  
  2958  	tk, v := unwrapValue(mv, &lt)
  2959  	am, ok := v.(map[string]any)
  2960  	if !ok {
  2961  		return &configErr{tk, fmt.Sprintf("Expected account limits to be a map/struct, got %+v", v)}
  2962  	}
  2963  
  2964  	for k, v := range am {
  2965  		tk, mv = unwrapValue(v, &lt)
  2966  		switch strings.ToLower(k) {
  2967  		case "max_connections", "max_conn":
  2968  			acc.mconns = int32(mv.(int64))
  2969  		case "max_subscriptions", "max_subs":
  2970  			acc.msubs = int32(mv.(int64))
  2971  		case "max_payload", "max_pay":
  2972  			acc.mpay = int32(mv.(int64))
  2973  		case "max_leafnodes", "max_leafs":
  2974  			acc.mleafs = int32(mv.(int64))
  2975  		default:
  2976  			if !tk.IsUsedVariable() {
  2977  				err := &configErr{tk, fmt.Sprintf("Unknown field %q parsing account limits", k)}
  2978  				*errors = append(*errors, err)
  2979  			}
  2980  		}
  2981  	}
  2982  
  2983  	return nil
  2984  }
  2985  
  2986  func parseAccountMsgTrace(mv any, topKey string, acc *Account) error {
  2987  	processDest := func(tk token, k string, v any) error {
  2988  		td, ok := v.(string)
  2989  		if !ok {
  2990  			return &configErr{tk, fmt.Sprintf("Field %q should be a string, got %T", k, v)}
  2991  		}
  2992  		if !IsValidPublishSubject(td) {
  2993  			return &configErr{tk, fmt.Sprintf("Trace destination %q is not valid", td)}
  2994  		}
  2995  		acc.traceDest = td
  2996  		return nil
  2997  	}
  2998  	processSampling := func(tk token, n int) error {
  2999  		if n <= 0 || n > 100 {
  3000  			return &configErr{tk, fmt.Sprintf("Ttrace destination sampling value %d is invalid, needs to be [1..100]", n)}
  3001  		}
  3002  		acc.traceDestSampling = n
  3003  		return nil
  3004  	}
  3005  
  3006  	var lt token
  3007  	tk, v := unwrapValue(mv, &lt)
  3008  	switch vv := v.(type) {
  3009  	case string:
  3010  		return processDest(tk, topKey, v)
  3011  	case map[string]any:
  3012  		for k, v := range vv {
  3013  			tk, v := unwrapValue(v, &lt)
  3014  			switch strings.ToLower(k) {
  3015  			case "dest":
  3016  				if err := processDest(tk, k, v); err != nil {
  3017  					return err
  3018  				}
  3019  			case "sampling":
  3020  				switch vv := v.(type) {
  3021  				case int64:
  3022  					if err := processSampling(tk, int(vv)); err != nil {
  3023  						return err
  3024  					}
  3025  				case string:
  3026  					s := strings.TrimSuffix(vv, "%")
  3027  					n, err := strconv.Atoi(s)
  3028  					if err != nil {
  3029  						return &configErr{tk, fmt.Sprintf("Invalid trace destination sampling value %q", vv)}
  3030  					}
  3031  					if err := processSampling(tk, n); err != nil {
  3032  						return err
  3033  					}
  3034  				default:
  3035  					return &configErr{tk, fmt.Sprintf("Trace destination sampling field %q should be an integer or a percentage, got %T", k, v)}
  3036  				}
  3037  			default:
  3038  				if !tk.IsUsedVariable() {
  3039  					return &configErr{tk, fmt.Sprintf("Unknown field %q parsing account message trace map/struct %q", k, topKey)}
  3040  				}
  3041  			}
  3042  		}
  3043  	default:
  3044  		return &configErr{tk, fmt.Sprintf("Expected account message trace %q to be a string or a map/struct, got %T", topKey, v)}
  3045  	}
  3046  	return nil
  3047  }
  3048  
  3049  // parseAccounts will parse the different accounts syntax.
  3050  func parseAccounts(v any, opts *Options, errors *[]error, warnings *[]error) error {
  3051  	var (
  3052  		importStreams  []*importStream
  3053  		importServices []*importService
  3054  		exportStreams  []*export
  3055  		exportServices []*export
  3056  		lt             token
  3057  	)
  3058  	defer convertPanicToErrorList(&lt, errors)
  3059  
  3060  	tk, v := unwrapValue(v, &lt)
  3061  	switch vv := v.(type) {
  3062  	// Simple array of account names.
  3063  	case []any, []string:
  3064  		m := make(map[string]struct{}, len(v.([]any)))
  3065  		for _, n := range v.([]any) {
  3066  			tk, name := unwrapValue(n, &lt)
  3067  			ns := name.(string)
  3068  			// Check for reserved names.
  3069  			if isReservedAccount(ns) {
  3070  				err := &configErr{tk, fmt.Sprintf("%q is a Reserved Account", ns)}
  3071  				*errors = append(*errors, err)
  3072  				continue
  3073  			}
  3074  			if _, ok := m[ns]; ok {
  3075  				err := &configErr{tk, fmt.Sprintf("Duplicate Account Entry: %s", ns)}
  3076  				*errors = append(*errors, err)
  3077  				continue
  3078  			}
  3079  			opts.Accounts = append(opts.Accounts, NewAccount(ns))
  3080  			m[ns] = struct{}{}
  3081  		}
  3082  	// More common map entry
  3083  	case map[string]any:
  3084  		// Track users across accounts, must be unique across
  3085  		// accounts and nkeys vs users.
  3086  		// We also want to check for users that may have been added in
  3087  		// parseAuthorization{} if that happened first.
  3088  		uorn := setupUsersAndNKeysDuplicateCheckMap(opts)
  3089  
  3090  		for aname, mv := range vv {
  3091  			tk, amv := unwrapValue(mv, &lt)
  3092  
  3093  			// Skip referenced config vars within the account block.
  3094  			if tk.IsUsedVariable() {
  3095  				continue
  3096  			}
  3097  
  3098  			// These should be maps.
  3099  			mv, ok := amv.(map[string]any)
  3100  			if !ok {
  3101  				err := &configErr{tk, "Expected map entries for accounts"}
  3102  				*errors = append(*errors, err)
  3103  				continue
  3104  			}
  3105  			if isReservedAccount(aname) {
  3106  				err := &configErr{tk, fmt.Sprintf("%q is a Reserved Account", aname)}
  3107  				*errors = append(*errors, err)
  3108  				continue
  3109  			}
  3110  			var (
  3111  				users   []*User
  3112  				nkeyUsr []*NkeyUser
  3113  				usersTk token
  3114  			)
  3115  			acc := NewAccount(aname)
  3116  			opts.Accounts = append(opts.Accounts, acc)
  3117  
  3118  			for k, v := range mv {
  3119  				tk, mv := unwrapValue(v, &lt)
  3120  				switch strings.ToLower(k) {
  3121  				case "nkey":
  3122  					nk, ok := mv.(string)
  3123  					if !ok || !nkeys.IsValidPublicAccountKey(nk) {
  3124  						err := &configErr{tk, fmt.Sprintf("Not a valid public nkey for an account: %q", mv)}
  3125  						*errors = append(*errors, err)
  3126  						continue
  3127  					}
  3128  					acc.Nkey = nk
  3129  				case "imports":
  3130  					streams, services, err := parseAccountImports(tk, acc, errors)
  3131  					if err != nil {
  3132  						*errors = append(*errors, err)
  3133  						continue
  3134  					}
  3135  					importStreams = append(importStreams, streams...)
  3136  					importServices = append(importServices, services...)
  3137  				case "exports":
  3138  					streams, services, err := parseAccountExports(tk, acc, errors)
  3139  					if err != nil {
  3140  						*errors = append(*errors, err)
  3141  						continue
  3142  					}
  3143  					exportStreams = append(exportStreams, streams...)
  3144  					exportServices = append(exportServices, services...)
  3145  				case "jetstream":
  3146  					err := parseJetStreamForAccount(mv, acc, errors)
  3147  					if err != nil {
  3148  						*errors = append(*errors, err)
  3149  						continue
  3150  					}
  3151  				case "users":
  3152  					var err error
  3153  					usersTk = tk
  3154  					nkeyUsr, users, err = parseUsers(mv, errors)
  3155  					if err != nil {
  3156  						*errors = append(*errors, err)
  3157  						continue
  3158  					}
  3159  				case "default_permissions":
  3160  					permissions, err := parseUserPermissions(tk, errors)
  3161  					if err != nil {
  3162  						*errors = append(*errors, err)
  3163  						continue
  3164  					}
  3165  					acc.defaultPerms = permissions
  3166  				case "mappings", "maps":
  3167  					err := parseAccountMappings(tk, acc, errors)
  3168  					if err != nil {
  3169  						*errors = append(*errors, err)
  3170  						continue
  3171  					}
  3172  				case "limits":
  3173  					err := parseAccountLimits(tk, acc, errors)
  3174  					if err != nil {
  3175  						*errors = append(*errors, err)
  3176  						continue
  3177  					}
  3178  				case "msg_trace", "trace_dest":
  3179  					if err := parseAccountMsgTrace(tk, k, acc); err != nil {
  3180  						*errors = append(*errors, err)
  3181  						continue
  3182  					}
  3183  					// If trace destination is set but no sampling, set it to 100%.
  3184  					if acc.traceDest != _EMPTY_ && acc.traceDestSampling == 0 {
  3185  						acc.traceDestSampling = 100
  3186  					} else if acc.traceDestSampling > 0 && acc.traceDest == _EMPTY_ {
  3187  						// If no trace destination is provided, no trace would be
  3188  						// triggered, so if the user set a sampling value expecting
  3189  						// something to happen, want and set the value to 0 for good
  3190  						// measure.
  3191  						*warnings = append(*warnings,
  3192  							&configErr{tk, "Trace destination sampling ignored since no destination was set"})
  3193  						acc.traceDestSampling = 0
  3194  					}
  3195  				default:
  3196  					if !tk.IsUsedVariable() {
  3197  						err := &unknownConfigFieldErr{
  3198  							field: k,
  3199  							configErr: configErr{
  3200  								token: tk,
  3201  							},
  3202  						}
  3203  						*errors = append(*errors, err)
  3204  					}
  3205  				}
  3206  			}
  3207  			// Report error if there is an authorization{} block
  3208  			// with u/p or token and any user defined in accounts{}
  3209  			if len(nkeyUsr) > 0 || len(users) > 0 {
  3210  				if opts.Username != _EMPTY_ {
  3211  					err := &configErr{usersTk, "Can not have a single user/pass and accounts"}
  3212  					*errors = append(*errors, err)
  3213  					continue
  3214  				}
  3215  				if opts.Authorization != _EMPTY_ {
  3216  					err := &configErr{usersTk, "Can not have a token and accounts"}
  3217  					*errors = append(*errors, err)
  3218  					continue
  3219  				}
  3220  			}
  3221  			applyDefaultPermissions(users, nkeyUsr, acc.defaultPerms)
  3222  			for _, u := range nkeyUsr {
  3223  				if _, ok := uorn[u.Nkey]; ok {
  3224  					err := &configErr{usersTk, fmt.Sprintf("Duplicate nkey %q detected", u.Nkey)}
  3225  					*errors = append(*errors, err)
  3226  					continue
  3227  				}
  3228  				uorn[u.Nkey] = struct{}{}
  3229  				u.Account = acc
  3230  			}
  3231  			opts.Nkeys = append(opts.Nkeys, nkeyUsr...)
  3232  			for _, u := range users {
  3233  				if _, ok := uorn[u.Username]; ok {
  3234  					err := &configErr{usersTk, fmt.Sprintf("Duplicate user %q detected", u.Username)}
  3235  					*errors = append(*errors, err)
  3236  					continue
  3237  				}
  3238  				uorn[u.Username] = struct{}{}
  3239  				u.Account = acc
  3240  			}
  3241  			opts.Users = append(opts.Users, users...)
  3242  		}
  3243  	}
  3244  	lt = tk
  3245  	// Bail already if there are previous errors.
  3246  	if len(*errors) > 0 {
  3247  		return nil
  3248  	}
  3249  
  3250  	// Parse Imports and Exports here after all accounts defined.
  3251  	// Do exports first since they need to be defined for imports to succeed
  3252  	// since we do permissions checks.
  3253  
  3254  	// Create a lookup map for accounts lookups.
  3255  	am := make(map[string]*Account, len(opts.Accounts))
  3256  	for _, a := range opts.Accounts {
  3257  		am[a.Name] = a
  3258  	}
  3259  	// Do stream exports
  3260  	for _, stream := range exportStreams {
  3261  		// Make array of accounts if applicable.
  3262  		var accounts []*Account
  3263  		for _, an := range stream.accs {
  3264  			ta := am[an]
  3265  			if ta == nil {
  3266  				msg := fmt.Sprintf("%q account not defined for stream export", an)
  3267  				*errors = append(*errors, &configErr{tk, msg})
  3268  				continue
  3269  			}
  3270  			accounts = append(accounts, ta)
  3271  		}
  3272  		if err := stream.acc.addStreamExportWithAccountPos(stream.sub, accounts, stream.tPos); err != nil {
  3273  			msg := fmt.Sprintf("Error adding stream export %q: %v", stream.sub, err)
  3274  			*errors = append(*errors, &configErr{tk, msg})
  3275  			continue
  3276  		}
  3277  	}
  3278  	for _, service := range exportServices {
  3279  		// Make array of accounts if applicable.
  3280  		var accounts []*Account
  3281  		for _, an := range service.accs {
  3282  			ta := am[an]
  3283  			if ta == nil {
  3284  				msg := fmt.Sprintf("%q account not defined for service export", an)
  3285  				*errors = append(*errors, &configErr{tk, msg})
  3286  				continue
  3287  			}
  3288  			accounts = append(accounts, ta)
  3289  		}
  3290  		if err := service.acc.addServiceExportWithResponseAndAccountPos(service.sub, service.rt, accounts, service.tPos); err != nil {
  3291  			msg := fmt.Sprintf("Error adding service export %q: %v", service.sub, err)
  3292  			*errors = append(*errors, &configErr{tk, msg})
  3293  			continue
  3294  		}
  3295  
  3296  		if service.rthr != 0 {
  3297  			// Response threshold was set in options.
  3298  			if err := service.acc.SetServiceExportResponseThreshold(service.sub, service.rthr); err != nil {
  3299  				msg := fmt.Sprintf("Error adding service export response threshold for %q: %v", service.sub, err)
  3300  				*errors = append(*errors, &configErr{tk, msg})
  3301  				continue
  3302  			}
  3303  		}
  3304  
  3305  		if service.lat != nil {
  3306  			// System accounts are on be default so just make sure we have not opted out..
  3307  			if opts.NoSystemAccount {
  3308  				msg := fmt.Sprintf("Error adding service latency sampling for %q: %v", service.sub, ErrNoSysAccount.Error())
  3309  				*errors = append(*errors, &configErr{tk, msg})
  3310  				continue
  3311  			}
  3312  
  3313  			if err := service.acc.TrackServiceExportWithSampling(service.sub, service.lat.subject, int(service.lat.sampling)); err != nil {
  3314  				msg := fmt.Sprintf("Error adding service latency sampling for %q on subject %q: %v", service.sub, service.lat.subject, err)
  3315  				*errors = append(*errors, &configErr{tk, msg})
  3316  				continue
  3317  			}
  3318  		}
  3319  
  3320  		if service.atrc {
  3321  			if err := service.acc.SetServiceExportAllowTrace(service.sub, true); err != nil {
  3322  				msg := fmt.Sprintf("Error adding allow_trace for %q: %v", service.sub, err)
  3323  				*errors = append(*errors, &configErr{tk, msg})
  3324  				continue
  3325  			}
  3326  		}
  3327  	}
  3328  	for _, stream := range importStreams {
  3329  		ta := am[stream.an]
  3330  		if ta == nil {
  3331  			msg := fmt.Sprintf("%q account not defined for stream import", stream.an)
  3332  			*errors = append(*errors, &configErr{tk, msg})
  3333  			continue
  3334  		}
  3335  		if stream.pre != _EMPTY_ {
  3336  			if err := stream.acc.addStreamImportWithClaim(ta, stream.sub, stream.pre, stream.atrc, nil); err != nil {
  3337  				msg := fmt.Sprintf("Error adding stream import %q: %v", stream.sub, err)
  3338  				*errors = append(*errors, &configErr{tk, msg})
  3339  				continue
  3340  			}
  3341  		} else {
  3342  			if err := stream.acc.addMappedStreamImportWithClaim(ta, stream.sub, stream.to, stream.atrc, nil); err != nil {
  3343  				msg := fmt.Sprintf("Error adding stream import %q: %v", stream.sub, err)
  3344  				*errors = append(*errors, &configErr{tk, msg})
  3345  				continue
  3346  			}
  3347  		}
  3348  	}
  3349  	for _, service := range importServices {
  3350  		ta := am[service.an]
  3351  		if ta == nil {
  3352  			msg := fmt.Sprintf("%q account not defined for service import", service.an)
  3353  			*errors = append(*errors, &configErr{tk, msg})
  3354  			continue
  3355  		}
  3356  		if service.to == _EMPTY_ {
  3357  			service.to = service.sub
  3358  		}
  3359  		if err := service.acc.AddServiceImport(ta, service.to, service.sub); err != nil {
  3360  			msg := fmt.Sprintf("Error adding service import %q: %v", service.sub, err)
  3361  			*errors = append(*errors, &configErr{tk, msg})
  3362  			continue
  3363  		}
  3364  		if err := service.acc.SetServiceImportSharing(ta, service.sub, service.share); err != nil {
  3365  			msg := fmt.Sprintf("Error setting service import sharing %q: %v", service.sub, err)
  3366  			*errors = append(*errors, &configErr{tk, msg})
  3367  			continue
  3368  		}
  3369  	}
  3370  
  3371  	return nil
  3372  }
  3373  
  3374  // Parse the account exports
  3375  func parseAccountExports(v any, acc *Account, errors *[]error) ([]*export, []*export, error) {
  3376  	var lt token
  3377  	defer convertPanicToErrorList(&lt, errors)
  3378  
  3379  	// This should be an array of objects/maps.
  3380  	tk, v := unwrapValue(v, &lt)
  3381  	ims, ok := v.([]any)
  3382  	if !ok {
  3383  		return nil, nil, &configErr{tk, fmt.Sprintf("Exports should be an array, got %T", v)}
  3384  	}
  3385  
  3386  	var services []*export
  3387  	var streams []*export
  3388  
  3389  	for _, v := range ims {
  3390  		// Should have stream or service
  3391  		stream, service, err := parseExportStreamOrService(v, errors)
  3392  		if err != nil {
  3393  			*errors = append(*errors, err)
  3394  			continue
  3395  		}
  3396  		if service != nil {
  3397  			service.acc = acc
  3398  			services = append(services, service)
  3399  		}
  3400  		if stream != nil {
  3401  			stream.acc = acc
  3402  			streams = append(streams, stream)
  3403  		}
  3404  	}
  3405  	return streams, services, nil
  3406  }
  3407  
  3408  // Parse the account imports
  3409  func parseAccountImports(v any, acc *Account, errors *[]error) ([]*importStream, []*importService, error) {
  3410  	var lt token
  3411  	defer convertPanicToErrorList(&lt, errors)
  3412  
  3413  	// This should be an array of objects/maps.
  3414  	tk, v := unwrapValue(v, &lt)
  3415  	ims, ok := v.([]any)
  3416  	if !ok {
  3417  		return nil, nil, &configErr{tk, fmt.Sprintf("Imports should be an array, got %T", v)}
  3418  	}
  3419  
  3420  	var services []*importService
  3421  	var streams []*importStream
  3422  	svcSubjects := map[string]*importService{}
  3423  
  3424  	for _, v := range ims {
  3425  		// Should have stream or service
  3426  		stream, service, err := parseImportStreamOrService(v, errors)
  3427  		if err != nil {
  3428  			*errors = append(*errors, err)
  3429  			continue
  3430  		}
  3431  		if service != nil {
  3432  			if dup := svcSubjects[service.to]; dup != nil {
  3433  				tk, _ := unwrapValue(v, &lt)
  3434  				err := &configErr{tk,
  3435  					fmt.Sprintf("Duplicate service import subject %q, previously used in import for account %q, subject %q",
  3436  						service.to, dup.an, dup.sub)}
  3437  				*errors = append(*errors, err)
  3438  				continue
  3439  			}
  3440  			svcSubjects[service.to] = service
  3441  			service.acc = acc
  3442  			services = append(services, service)
  3443  		}
  3444  		if stream != nil {
  3445  			stream.acc = acc
  3446  			streams = append(streams, stream)
  3447  		}
  3448  	}
  3449  	return streams, services, nil
  3450  }
  3451  
  3452  // Helper to parse an embedded account description for imported services or streams.
  3453  func parseAccount(v map[string]any, errors *[]error) (string, string, error) {
  3454  	var lt token
  3455  	defer convertPanicToErrorList(&lt, errors)
  3456  
  3457  	var accountName, subject string
  3458  	for mk, mv := range v {
  3459  		tk, mv := unwrapValue(mv, &lt)
  3460  		switch strings.ToLower(mk) {
  3461  		case "account":
  3462  			accountName = mv.(string)
  3463  		case "subject":
  3464  			subject = mv.(string)
  3465  		default:
  3466  			if !tk.IsUsedVariable() {
  3467  				err := &unknownConfigFieldErr{
  3468  					field: mk,
  3469  					configErr: configErr{
  3470  						token: tk,
  3471  					},
  3472  				}
  3473  				*errors = append(*errors, err)
  3474  			}
  3475  		}
  3476  	}
  3477  	return accountName, subject, nil
  3478  }
  3479  
  3480  // Parse an export stream or service.
  3481  // e.g.
  3482  // {stream: "public.>"} # No accounts means public.
  3483  // {stream: "synadia.private.>", accounts: [cncf, natsio]}
  3484  // {service: "pub.request"} # No accounts means public.
  3485  // {service: "pub.special.request", accounts: [nats.io]}
  3486  func parseExportStreamOrService(v any, errors *[]error) (*export, *export, error) {
  3487  	var (
  3488  		curStream  *export
  3489  		curService *export
  3490  		accounts   []string
  3491  		rt         ServiceRespType
  3492  		rtSeen     bool
  3493  		rtToken    token
  3494  		lat        *serviceLatency
  3495  		threshSeen bool
  3496  		thresh     time.Duration
  3497  		latToken   token
  3498  		lt         token
  3499  		accTokPos  uint
  3500  		atrc       bool
  3501  		atrcSeen   bool
  3502  		atrcToken  token
  3503  	)
  3504  	defer convertPanicToErrorList(&lt, errors)
  3505  
  3506  	tk, v := unwrapValue(v, &lt)
  3507  	vv, ok := v.(map[string]any)
  3508  	if !ok {
  3509  		return nil, nil, &configErr{tk, fmt.Sprintf("Export Items should be a map with type entry, got %T", v)}
  3510  	}
  3511  	for mk, mv := range vv {
  3512  		tk, mv := unwrapValue(mv, &lt)
  3513  		switch strings.ToLower(mk) {
  3514  		case "stream":
  3515  			if curService != nil {
  3516  				err := &configErr{tk, fmt.Sprintf("Detected stream %q but already saw a service", mv)}
  3517  				*errors = append(*errors, err)
  3518  				continue
  3519  			}
  3520  			if rtToken != nil {
  3521  				err := &configErr{rtToken, "Detected response directive on non-service"}
  3522  				*errors = append(*errors, err)
  3523  				continue
  3524  			}
  3525  			if latToken != nil {
  3526  				err := &configErr{latToken, "Detected latency directive on non-service"}
  3527  				*errors = append(*errors, err)
  3528  				continue
  3529  			}
  3530  			if atrcToken != nil {
  3531  				err := &configErr{atrcToken, "Detected allow_trace directive on non-service"}
  3532  				*errors = append(*errors, err)
  3533  				continue
  3534  			}
  3535  			mvs, ok := mv.(string)
  3536  			if !ok {
  3537  				err := &configErr{tk, fmt.Sprintf("Expected stream name to be string, got %T", mv)}
  3538  				*errors = append(*errors, err)
  3539  				continue
  3540  			}
  3541  			curStream = &export{sub: mvs}
  3542  			if accounts != nil {
  3543  				curStream.accs = accounts
  3544  			}
  3545  		case "service":
  3546  			if curStream != nil {
  3547  				err := &configErr{tk, fmt.Sprintf("Detected service %q but already saw a stream", mv)}
  3548  				*errors = append(*errors, err)
  3549  				continue
  3550  			}
  3551  			mvs, ok := mv.(string)
  3552  			if !ok {
  3553  				err := &configErr{tk, fmt.Sprintf("Expected service name to be string, got %T", mv)}
  3554  				*errors = append(*errors, err)
  3555  				continue
  3556  			}
  3557  			curService = &export{sub: mvs}
  3558  			if accounts != nil {
  3559  				curService.accs = accounts
  3560  			}
  3561  			if rtSeen {
  3562  				curService.rt = rt
  3563  			}
  3564  			if lat != nil {
  3565  				curService.lat = lat
  3566  			}
  3567  			if threshSeen {
  3568  				curService.rthr = thresh
  3569  			}
  3570  			if atrcSeen {
  3571  				curService.atrc = atrc
  3572  			}
  3573  		case "response", "response_type":
  3574  			if rtSeen {
  3575  				err := &configErr{tk, "Duplicate response type definition"}
  3576  				*errors = append(*errors, err)
  3577  				continue
  3578  			}
  3579  			rtSeen = true
  3580  			rtToken = tk
  3581  			mvs, ok := mv.(string)
  3582  			if !ok {
  3583  				err := &configErr{tk, fmt.Sprintf("Expected response type to be string, got %T", mv)}
  3584  				*errors = append(*errors, err)
  3585  				continue
  3586  			}
  3587  			switch strings.ToLower(mvs) {
  3588  			case "single", "singleton":
  3589  				rt = Singleton
  3590  			case "stream":
  3591  				rt = Streamed
  3592  			case "chunk", "chunked":
  3593  				rt = Chunked
  3594  			default:
  3595  				err := &configErr{tk, fmt.Sprintf("Unknown response type: %q", mvs)}
  3596  				*errors = append(*errors, err)
  3597  				continue
  3598  			}
  3599  			if curService != nil {
  3600  				curService.rt = rt
  3601  			}
  3602  			if curStream != nil {
  3603  				err := &configErr{tk, "Detected response directive on non-service"}
  3604  				*errors = append(*errors, err)
  3605  			}
  3606  		case "threshold", "response_threshold", "response_max_time", "response_time":
  3607  			if threshSeen {
  3608  				err := &configErr{tk, "Duplicate response threshold detected"}
  3609  				*errors = append(*errors, err)
  3610  				continue
  3611  			}
  3612  			threshSeen = true
  3613  			mvs, ok := mv.(string)
  3614  			if !ok {
  3615  				err := &configErr{tk, fmt.Sprintf("Expected response threshold to be a parseable time duration, got %T", mv)}
  3616  				*errors = append(*errors, err)
  3617  				continue
  3618  			}
  3619  			var err error
  3620  			thresh, err = time.ParseDuration(mvs)
  3621  			if err != nil {
  3622  				err := &configErr{tk, fmt.Sprintf("Expected response threshold to be a parseable time duration, got %q", mvs)}
  3623  				*errors = append(*errors, err)
  3624  				continue
  3625  			}
  3626  			if curService != nil {
  3627  				curService.rthr = thresh
  3628  			}
  3629  			if curStream != nil {
  3630  				err := &configErr{tk, "Detected response directive on non-service"}
  3631  				*errors = append(*errors, err)
  3632  			}
  3633  		case "accounts":
  3634  			for _, iv := range mv.([]any) {
  3635  				_, mv := unwrapValue(iv, &lt)
  3636  				accounts = append(accounts, mv.(string))
  3637  			}
  3638  			if curStream != nil {
  3639  				curStream.accs = accounts
  3640  			} else if curService != nil {
  3641  				curService.accs = accounts
  3642  			}
  3643  		case "latency":
  3644  			latToken = tk
  3645  			var err error
  3646  			lat, err = parseServiceLatency(tk, mv)
  3647  			if err != nil {
  3648  				*errors = append(*errors, err)
  3649  				continue
  3650  			}
  3651  			if curStream != nil {
  3652  				err = &configErr{tk, "Detected latency directive on non-service"}
  3653  				*errors = append(*errors, err)
  3654  				continue
  3655  			}
  3656  			if curService != nil {
  3657  				curService.lat = lat
  3658  			}
  3659  		case "account_token_position":
  3660  			accTokPos = uint(mv.(int64))
  3661  		case "allow_trace":
  3662  			atrcSeen = true
  3663  			atrcToken = tk
  3664  			atrc = mv.(bool)
  3665  			if curStream != nil {
  3666  				*errors = append(*errors,
  3667  					&configErr{tk, "Detected allow_trace directive on non-service"})
  3668  				continue
  3669  			}
  3670  			if curService != nil {
  3671  				curService.atrc = atrc
  3672  			}
  3673  		default:
  3674  			if !tk.IsUsedVariable() {
  3675  				err := &unknownConfigFieldErr{
  3676  					field: mk,
  3677  					configErr: configErr{
  3678  						token: tk,
  3679  					},
  3680  				}
  3681  				*errors = append(*errors, err)
  3682  			}
  3683  		}
  3684  	}
  3685  	if curStream != nil {
  3686  		curStream.tPos = accTokPos
  3687  	}
  3688  	if curService != nil {
  3689  		curService.tPos = accTokPos
  3690  	}
  3691  	return curStream, curService, nil
  3692  }
  3693  
  3694  // parseServiceLatency returns a latency config block.
  3695  func parseServiceLatency(root token, v any) (l *serviceLatency, retErr error) {
  3696  	var lt token
  3697  	defer convertPanicToError(&lt, &retErr)
  3698  
  3699  	if subject, ok := v.(string); ok {
  3700  		return &serviceLatency{
  3701  			subject:  subject,
  3702  			sampling: DEFAULT_SERVICE_LATENCY_SAMPLING,
  3703  		}, nil
  3704  	}
  3705  
  3706  	latency, ok := v.(map[string]any)
  3707  	if !ok {
  3708  		return nil, &configErr{token: root,
  3709  			reason: fmt.Sprintf("Expected latency entry to be a map/struct or string, got %T", v)}
  3710  	}
  3711  
  3712  	sl := serviceLatency{
  3713  		sampling: DEFAULT_SERVICE_LATENCY_SAMPLING,
  3714  	}
  3715  
  3716  	// Read sampling value.
  3717  	if v, ok := latency["sampling"]; ok {
  3718  		tk, v := unwrapValue(v, &lt)
  3719  		header := false
  3720  		var sample int64
  3721  		switch vv := v.(type) {
  3722  		case int64:
  3723  			// Sample is an int, like 50.
  3724  			sample = vv
  3725  		case string:
  3726  			// Sample is a string, like "50%".
  3727  			if strings.ToLower(strings.TrimSpace(vv)) == "headers" {
  3728  				header = true
  3729  				sample = 0
  3730  				break
  3731  			}
  3732  			s := strings.TrimSuffix(vv, "%")
  3733  			n, err := strconv.Atoi(s)
  3734  			if err != nil {
  3735  				return nil, &configErr{token: tk,
  3736  					reason: fmt.Sprintf("Failed to parse latency sample: %v", err)}
  3737  			}
  3738  			sample = int64(n)
  3739  		default:
  3740  			return nil, &configErr{token: tk,
  3741  				reason: fmt.Sprintf("Expected latency sample to be a string or map/struct, got %T", v)}
  3742  		}
  3743  		if !header {
  3744  			if sample < 1 || sample > 100 {
  3745  				return nil, &configErr{token: tk,
  3746  					reason: ErrBadSampling.Error()}
  3747  			}
  3748  		}
  3749  
  3750  		sl.sampling = int8(sample)
  3751  	}
  3752  
  3753  	// Read subject value.
  3754  	v, ok = latency["subject"]
  3755  	if !ok {
  3756  		return nil, &configErr{token: root,
  3757  			reason: "Latency subject required, but missing"}
  3758  	}
  3759  
  3760  	tk, v := unwrapValue(v, &lt)
  3761  	subject, ok := v.(string)
  3762  	if !ok {
  3763  		return nil, &configErr{token: tk,
  3764  			reason: fmt.Sprintf("Expected latency subject to be a string, got %T", subject)}
  3765  	}
  3766  	sl.subject = subject
  3767  
  3768  	return &sl, nil
  3769  }
  3770  
  3771  // Parse an import stream or service.
  3772  // e.g.
  3773  // {stream: {account: "synadia", subject:"public.synadia"}, prefix: "imports.synadia"}
  3774  // {stream: {account: "synadia", subject:"synadia.private.*"}}
  3775  // {service: {account: "synadia", subject: "pub.special.request"}, to: "synadia.request"}
  3776  func parseImportStreamOrService(v any, errors *[]error) (*importStream, *importService, error) {
  3777  	var (
  3778  		curStream  *importStream
  3779  		curService *importService
  3780  		pre, to    string
  3781  		share      bool
  3782  		lt         token
  3783  		atrc       bool
  3784  		atrcSeen   bool
  3785  		atrcToken  token
  3786  	)
  3787  	defer convertPanicToErrorList(&lt, errors)
  3788  
  3789  	tk, mv := unwrapValue(v, &lt)
  3790  	vv, ok := mv.(map[string]any)
  3791  	if !ok {
  3792  		return nil, nil, &configErr{tk, fmt.Sprintf("Import Items should be a map with type entry, got %T", mv)}
  3793  	}
  3794  	for mk, mv := range vv {
  3795  		tk, mv := unwrapValue(mv, &lt)
  3796  		switch strings.ToLower(mk) {
  3797  		case "stream":
  3798  			if curService != nil {
  3799  				err := &configErr{tk, "Detected stream but already saw a service"}
  3800  				*errors = append(*errors, err)
  3801  				continue
  3802  			}
  3803  			ac, ok := mv.(map[string]any)
  3804  			if !ok {
  3805  				err := &configErr{tk, fmt.Sprintf("Stream entry should be an account map, got %T", mv)}
  3806  				*errors = append(*errors, err)
  3807  				continue
  3808  			}
  3809  			// Make sure this is a map with account and subject
  3810  			accountName, subject, err := parseAccount(ac, errors)
  3811  			if err != nil {
  3812  				*errors = append(*errors, err)
  3813  				continue
  3814  			}
  3815  			if accountName == _EMPTY_ || subject == _EMPTY_ {
  3816  				err := &configErr{tk, "Expect an account name and a subject"}
  3817  				*errors = append(*errors, err)
  3818  				continue
  3819  			}
  3820  			curStream = &importStream{an: accountName, sub: subject}
  3821  			if to != _EMPTY_ {
  3822  				curStream.to = to
  3823  			}
  3824  			if pre != _EMPTY_ {
  3825  				curStream.pre = pre
  3826  			}
  3827  			if atrcSeen {
  3828  				curStream.atrc = atrc
  3829  			}
  3830  		case "service":
  3831  			if curStream != nil {
  3832  				err := &configErr{tk, "Detected service but already saw a stream"}
  3833  				*errors = append(*errors, err)
  3834  				continue
  3835  			}
  3836  			if atrcToken != nil {
  3837  				err := &configErr{atrcToken, "Detected allow_trace directive on a non-stream"}
  3838  				*errors = append(*errors, err)
  3839  				continue
  3840  			}
  3841  			ac, ok := mv.(map[string]any)
  3842  			if !ok {
  3843  				err := &configErr{tk, fmt.Sprintf("Service entry should be an account map, got %T", mv)}
  3844  				*errors = append(*errors, err)
  3845  				continue
  3846  			}
  3847  			// Make sure this is a map with account and subject
  3848  			accountName, subject, err := parseAccount(ac, errors)
  3849  			if err != nil {
  3850  				*errors = append(*errors, err)
  3851  				continue
  3852  			}
  3853  			if accountName == _EMPTY_ || subject == _EMPTY_ {
  3854  				err := &configErr{tk, "Expect an account name and a subject"}
  3855  				*errors = append(*errors, err)
  3856  				continue
  3857  			}
  3858  			curService = &importService{an: accountName, sub: subject}
  3859  			if to != _EMPTY_ {
  3860  				curService.to = to
  3861  			} else {
  3862  				curService.to = subject
  3863  			}
  3864  			curService.share = share
  3865  		case "prefix":
  3866  			pre = mv.(string)
  3867  			if curStream != nil {
  3868  				curStream.pre = pre
  3869  			}
  3870  		case "to":
  3871  			to = mv.(string)
  3872  			if curService != nil {
  3873  				curService.to = to
  3874  			}
  3875  			if curStream != nil {
  3876  				curStream.to = to
  3877  				if curStream.pre != _EMPTY_ {
  3878  					err := &configErr{tk, "Stream import can not have a 'prefix' and a 'to' property"}
  3879  					*errors = append(*errors, err)
  3880  					continue
  3881  				}
  3882  			}
  3883  		case "share":
  3884  			share = mv.(bool)
  3885  			if curService != nil {
  3886  				curService.share = share
  3887  			}
  3888  		case "allow_trace":
  3889  			if curService != nil {
  3890  				err := &configErr{tk, "Detected allow_trace directive on a non-stream"}
  3891  				*errors = append(*errors, err)
  3892  				continue
  3893  			}
  3894  			atrcSeen = true
  3895  			atrc = mv.(bool)
  3896  			atrcToken = tk
  3897  			if curStream != nil {
  3898  				curStream.atrc = atrc
  3899  			}
  3900  		default:
  3901  			if !tk.IsUsedVariable() {
  3902  				err := &unknownConfigFieldErr{
  3903  					field: mk,
  3904  					configErr: configErr{
  3905  						token: tk,
  3906  					},
  3907  				}
  3908  				*errors = append(*errors, err)
  3909  			}
  3910  		}
  3911  
  3912  	}
  3913  	return curStream, curService, nil
  3914  }
  3915  
  3916  // Apply permission defaults to users/nkeyuser that don't have their own.
  3917  func applyDefaultPermissions(users []*User, nkeys []*NkeyUser, defaultP *Permissions) {
  3918  	if defaultP == nil {
  3919  		return
  3920  	}
  3921  	for _, user := range users {
  3922  		if user.Permissions == nil {
  3923  			user.Permissions = defaultP
  3924  		}
  3925  	}
  3926  	for _, user := range nkeys {
  3927  		if user.Permissions == nil {
  3928  			user.Permissions = defaultP
  3929  		}
  3930  	}
  3931  }
  3932  
  3933  // Helper function to parse Authorization configs.
  3934  func parseAuthorization(v any, errors *[]error) (*authorization, error) {
  3935  	var (
  3936  		am   map[string]any
  3937  		tk   token
  3938  		lt   token
  3939  		auth = &authorization{}
  3940  	)
  3941  	defer convertPanicToErrorList(&lt, errors)
  3942  
  3943  	_, v = unwrapValue(v, &lt)
  3944  	am = v.(map[string]any)
  3945  	for mk, mv := range am {
  3946  		tk, mv = unwrapValue(mv, &lt)
  3947  		switch strings.ToLower(mk) {
  3948  		case "user", "username":
  3949  			auth.user = mv.(string)
  3950  		case "pass", "password":
  3951  			auth.pass = mv.(string)
  3952  		case "token":
  3953  			auth.token = mv.(string)
  3954  		case "timeout":
  3955  			at := float64(1)
  3956  			switch mv := mv.(type) {
  3957  			case int64:
  3958  				at = float64(mv)
  3959  			case float64:
  3960  				at = mv
  3961  			}
  3962  			auth.timeout = at
  3963  		case "users":
  3964  			nkeys, users, err := parseUsers(tk, errors)
  3965  			if err != nil {
  3966  				*errors = append(*errors, err)
  3967  				continue
  3968  			}
  3969  			auth.users = users
  3970  			auth.nkeys = nkeys
  3971  		case "default_permission", "default_permissions", "permissions":
  3972  			permissions, err := parseUserPermissions(tk, errors)
  3973  			if err != nil {
  3974  				*errors = append(*errors, err)
  3975  				continue
  3976  			}
  3977  			auth.defaultPermissions = permissions
  3978  		case "auth_callout", "auth_hook":
  3979  			ac, err := parseAuthCallout(tk, errors)
  3980  			if err != nil {
  3981  				*errors = append(*errors, err)
  3982  				continue
  3983  			}
  3984  			auth.callout = ac
  3985  		default:
  3986  			if !tk.IsUsedVariable() {
  3987  				err := &unknownConfigFieldErr{
  3988  					field: mk,
  3989  					configErr: configErr{
  3990  						token: tk,
  3991  					},
  3992  				}
  3993  				*errors = append(*errors, err)
  3994  			}
  3995  			continue
  3996  		}
  3997  
  3998  		applyDefaultPermissions(auth.users, auth.nkeys, auth.defaultPermissions)
  3999  	}
  4000  	return auth, nil
  4001  }
  4002  
  4003  // Helper function to parse multiple users array with optional permissions.
  4004  func parseUsers(mv any, errors *[]error) ([]*NkeyUser, []*User, error) {
  4005  	var (
  4006  		tk    token
  4007  		lt    token
  4008  		keys  []*NkeyUser
  4009  		users = []*User{}
  4010  	)
  4011  	defer convertPanicToErrorList(&lt, errors)
  4012  	tk, mv = unwrapValue(mv, &lt)
  4013  
  4014  	// Make sure we have an array
  4015  	uv, ok := mv.([]any)
  4016  	if !ok {
  4017  		return nil, nil, &configErr{tk, fmt.Sprintf("Expected users field to be an array, got %v", mv)}
  4018  	}
  4019  	for _, u := range uv {
  4020  		tk, u = unwrapValue(u, &lt)
  4021  
  4022  		// Check its a map/struct
  4023  		um, ok := u.(map[string]any)
  4024  		if !ok {
  4025  			err := &configErr{tk, fmt.Sprintf("Expected user entry to be a map/struct, got %v", u)}
  4026  			*errors = append(*errors, err)
  4027  			continue
  4028  		}
  4029  
  4030  		var (
  4031  			user  = &User{}
  4032  			nkey  = &NkeyUser{}
  4033  			perms *Permissions
  4034  			err   error
  4035  		)
  4036  		for k, v := range um {
  4037  			// Also needs to unwrap first
  4038  			tk, v = unwrapValue(v, &lt)
  4039  
  4040  			switch strings.ToLower(k) {
  4041  			case "nkey":
  4042  				nkey.Nkey = v.(string)
  4043  			case "user", "username":
  4044  				user.Username = v.(string)
  4045  			case "pass", "password":
  4046  				user.Password = v.(string)
  4047  			case "permission", "permissions", "authorization":
  4048  				perms, err = parseUserPermissions(tk, errors)
  4049  				if err != nil {
  4050  					*errors = append(*errors, err)
  4051  					continue
  4052  				}
  4053  			case "allowed_connection_types", "connection_types", "clients":
  4054  				cts := parseAllowedConnectionTypes(tk, &lt, v, errors)
  4055  				nkey.AllowedConnectionTypes = cts
  4056  				user.AllowedConnectionTypes = cts
  4057  			default:
  4058  				if !tk.IsUsedVariable() {
  4059  					err := &unknownConfigFieldErr{
  4060  						field: k,
  4061  						configErr: configErr{
  4062  							token: tk,
  4063  						},
  4064  					}
  4065  					*errors = append(*errors, err)
  4066  					continue
  4067  				}
  4068  			}
  4069  		}
  4070  		// Place perms if we have them.
  4071  		if perms != nil {
  4072  			// nkey takes precedent.
  4073  			if nkey.Nkey != _EMPTY_ {
  4074  				nkey.Permissions = perms
  4075  			} else {
  4076  				user.Permissions = perms
  4077  			}
  4078  		}
  4079  
  4080  		// Check to make sure we have at least an nkey or username <password> defined.
  4081  		if nkey.Nkey == _EMPTY_ && user.Username == _EMPTY_ {
  4082  			return nil, nil, &configErr{tk, "User entry requires a user"}
  4083  		} else if nkey.Nkey != _EMPTY_ {
  4084  			// Make sure the nkey a proper public nkey for a user..
  4085  			if !nkeys.IsValidPublicUserKey(nkey.Nkey) {
  4086  				return nil, nil, &configErr{tk, "Not a valid public nkey for a user"}
  4087  			}
  4088  			// If we have user or password defined here that is an error.
  4089  			if user.Username != _EMPTY_ || user.Password != _EMPTY_ {
  4090  				return nil, nil, &configErr{tk, "Nkey users do not take usernames or passwords"}
  4091  			}
  4092  			keys = append(keys, nkey)
  4093  		} else {
  4094  			users = append(users, user)
  4095  		}
  4096  	}
  4097  	return keys, users, nil
  4098  }
  4099  
  4100  func parseAllowedConnectionTypes(tk token, lt *token, mv any, errors *[]error) map[string]struct{} {
  4101  	cts, err := parseStringArray("allowed connection types", tk, lt, mv, errors)
  4102  	// If error, it has already been added to the `errors` array, simply return
  4103  	if err != nil {
  4104  		return nil
  4105  	}
  4106  	m, err := convertAllowedConnectionTypes(cts)
  4107  	if err != nil {
  4108  		*errors = append(*errors, &configErr{tk, err.Error()})
  4109  	}
  4110  	return m
  4111  }
  4112  
  4113  // Helper function to parse auth callouts.
  4114  func parseAuthCallout(mv any, errors *[]error) (*AuthCallout, error) {
  4115  	var (
  4116  		tk token
  4117  		lt token
  4118  		ac = &AuthCallout{}
  4119  	)
  4120  	defer convertPanicToErrorList(&lt, errors)
  4121  
  4122  	tk, mv = unwrapValue(mv, &lt)
  4123  	pm, ok := mv.(map[string]any)
  4124  	if !ok {
  4125  		return nil, &configErr{tk, fmt.Sprintf("Expected authorization callout to be a map/struct, got %+v", mv)}
  4126  	}
  4127  	for k, v := range pm {
  4128  		tk, mv = unwrapValue(v, &lt)
  4129  
  4130  		switch strings.ToLower(k) {
  4131  		case "issuer":
  4132  			ac.Issuer = mv.(string)
  4133  			if !nkeys.IsValidPublicAccountKey(ac.Issuer) {
  4134  				return nil, &configErr{tk, fmt.Sprintf("Expected callout user to be a valid public account nkey, got %q", ac.Issuer)}
  4135  			}
  4136  		case "account", "acc":
  4137  			ac.Account = mv.(string)
  4138  		case "auth_users", "users":
  4139  			aua, ok := mv.([]any)
  4140  			if !ok {
  4141  				return nil, &configErr{tk, fmt.Sprintf("Expected auth_users field to be an array, got %T", v)}
  4142  			}
  4143  			for _, uv := range aua {
  4144  				_, uv = unwrapValue(uv, &lt)
  4145  				ac.AuthUsers = append(ac.AuthUsers, uv.(string))
  4146  			}
  4147  		case "xkey", "key":
  4148  			ac.XKey = mv.(string)
  4149  			if !nkeys.IsValidPublicCurveKey(ac.XKey) {
  4150  				return nil, &configErr{tk, fmt.Sprintf("Expected callout xkey to be a valid public xkey, got %q", ac.XKey)}
  4151  			}
  4152  		default:
  4153  			if !tk.IsUsedVariable() {
  4154  				err := &configErr{tk, fmt.Sprintf("Unknown field %q parsing authorization callout", k)}
  4155  				*errors = append(*errors, err)
  4156  			}
  4157  		}
  4158  	}
  4159  	// Make sure we have all defined. All fields are required.
  4160  	// If no account specified, selet $G.
  4161  	if ac.Account == _EMPTY_ {
  4162  		ac.Account = globalAccountName
  4163  	}
  4164  	if ac.Issuer == _EMPTY_ {
  4165  		return nil, &configErr{tk, "Authorization callouts require an issuer to be specified"}
  4166  	}
  4167  	if len(ac.AuthUsers) == 0 {
  4168  		return nil, &configErr{tk, "Authorization callouts require authorized users to be specified"}
  4169  	}
  4170  	return ac, nil
  4171  }
  4172  
  4173  // Helper function to parse user/account permissions
  4174  func parseUserPermissions(mv any, errors *[]error) (*Permissions, error) {
  4175  	var (
  4176  		tk token
  4177  		lt token
  4178  		p  = &Permissions{}
  4179  	)
  4180  	defer convertPanicToErrorList(&lt, errors)
  4181  
  4182  	tk, mv = unwrapValue(mv, &lt)
  4183  	pm, ok := mv.(map[string]any)
  4184  	if !ok {
  4185  		return nil, &configErr{tk, fmt.Sprintf("Expected permissions to be a map/struct, got %+v", mv)}
  4186  	}
  4187  	for k, v := range pm {
  4188  		tk, mv = unwrapValue(v, &lt)
  4189  
  4190  		switch strings.ToLower(k) {
  4191  		// For routes:
  4192  		// Import is Publish
  4193  		// Export is Subscribe
  4194  		case "pub", "publish", "import":
  4195  			perms, err := parseVariablePermissions(mv, errors)
  4196  			if err != nil {
  4197  				*errors = append(*errors, err)
  4198  				continue
  4199  			}
  4200  			p.Publish = perms
  4201  		case "sub", "subscribe", "export":
  4202  			perms, err := parseVariablePermissions(mv, errors)
  4203  			if err != nil {
  4204  				*errors = append(*errors, err)
  4205  				continue
  4206  			}
  4207  			p.Subscribe = perms
  4208  		case "publish_allow_responses", "allow_responses":
  4209  			rp := &ResponsePermission{
  4210  				MaxMsgs: DEFAULT_ALLOW_RESPONSE_MAX_MSGS,
  4211  				Expires: DEFAULT_ALLOW_RESPONSE_EXPIRATION,
  4212  			}
  4213  			// Try boolean first
  4214  			responses, ok := mv.(bool)
  4215  			if ok {
  4216  				if responses {
  4217  					p.Response = rp
  4218  				}
  4219  			} else {
  4220  				p.Response = parseAllowResponses(v, errors)
  4221  			}
  4222  			if p.Response != nil {
  4223  				if p.Publish == nil {
  4224  					p.Publish = &SubjectPermission{}
  4225  				}
  4226  				if p.Publish.Allow == nil {
  4227  					// We turn off the blanket allow statement.
  4228  					p.Publish.Allow = []string{}
  4229  				}
  4230  			}
  4231  		default:
  4232  			if !tk.IsUsedVariable() {
  4233  				err := &configErr{tk, fmt.Sprintf("Unknown field %q parsing permissions", k)}
  4234  				*errors = append(*errors, err)
  4235  			}
  4236  		}
  4237  	}
  4238  	return p, nil
  4239  }
  4240  
  4241  // Top level parser for authorization configurations.
  4242  func parseVariablePermissions(v any, errors *[]error) (*SubjectPermission, error) {
  4243  	switch vv := v.(type) {
  4244  	case map[string]any:
  4245  		// New style with allow and/or deny properties.
  4246  		return parseSubjectPermission(vv, errors)
  4247  	default:
  4248  		// Old style
  4249  		return parseOldPermissionStyle(v, errors)
  4250  	}
  4251  }
  4252  
  4253  // Helper function to parse subject singletons and/or arrays
  4254  func parsePermSubjects(v any, errors *[]error) ([]string, error) {
  4255  	var lt token
  4256  	defer convertPanicToErrorList(&lt, errors)
  4257  
  4258  	tk, v := unwrapValue(v, &lt)
  4259  
  4260  	var subjects []string
  4261  	switch vv := v.(type) {
  4262  	case string:
  4263  		subjects = append(subjects, vv)
  4264  	case []string:
  4265  		subjects = vv
  4266  	case []any:
  4267  		for _, i := range vv {
  4268  			tk, i := unwrapValue(i, &lt)
  4269  
  4270  			subject, ok := i.(string)
  4271  			if !ok {
  4272  				return nil, &configErr{tk, "Subject in permissions array cannot be cast to string"}
  4273  			}
  4274  			subjects = append(subjects, subject)
  4275  		}
  4276  	default:
  4277  		return nil, &configErr{tk, fmt.Sprintf("Expected subject permissions to be a subject, or array of subjects, got %T", v)}
  4278  	}
  4279  	if err := checkPermSubjectArray(subjects); err != nil {
  4280  		return nil, &configErr{tk, err.Error()}
  4281  	}
  4282  	return subjects, nil
  4283  }
  4284  
  4285  // Helper function to parse a ResponsePermission.
  4286  func parseAllowResponses(v any, errors *[]error) *ResponsePermission {
  4287  	var lt token
  4288  	defer convertPanicToErrorList(&lt, errors)
  4289  
  4290  	tk, v := unwrapValue(v, &lt)
  4291  	// Check if this is a map.
  4292  	pm, ok := v.(map[string]any)
  4293  	if !ok {
  4294  		err := &configErr{tk, "error parsing response permissions, expected a boolean or a map"}
  4295  		*errors = append(*errors, err)
  4296  		return nil
  4297  	}
  4298  
  4299  	rp := &ResponsePermission{
  4300  		MaxMsgs: DEFAULT_ALLOW_RESPONSE_MAX_MSGS,
  4301  		Expires: DEFAULT_ALLOW_RESPONSE_EXPIRATION,
  4302  	}
  4303  
  4304  	for k, v := range pm {
  4305  		tk, v = unwrapValue(v, &lt)
  4306  		switch strings.ToLower(k) {
  4307  		case "max", "max_msgs", "max_messages", "max_responses":
  4308  			max := int(v.(int64))
  4309  			// Negative values are accepted (mean infinite), and 0
  4310  			// means default value (set above).
  4311  			if max != 0 {
  4312  				rp.MaxMsgs = max
  4313  			}
  4314  		case "expires", "expiration", "ttl":
  4315  			wd, ok := v.(string)
  4316  			if ok {
  4317  				ttl, err := time.ParseDuration(wd)
  4318  				if err != nil {
  4319  					err := &configErr{tk, fmt.Sprintf("error parsing expires: %v", err)}
  4320  					*errors = append(*errors, err)
  4321  					return nil
  4322  				}
  4323  				// Negative values are accepted (mean infinite), and 0
  4324  				// means default value (set above).
  4325  				if ttl != 0 {
  4326  					rp.Expires = ttl
  4327  				}
  4328  			} else {
  4329  				err := &configErr{tk, "error parsing expires, not a duration string"}
  4330  				*errors = append(*errors, err)
  4331  				return nil
  4332  			}
  4333  		default:
  4334  			if !tk.IsUsedVariable() {
  4335  				err := &configErr{tk, fmt.Sprintf("Unknown field %q parsing permissions", k)}
  4336  				*errors = append(*errors, err)
  4337  			}
  4338  		}
  4339  	}
  4340  	return rp
  4341  }
  4342  
  4343  // Helper function to parse old style authorization configs.
  4344  func parseOldPermissionStyle(v any, errors *[]error) (*SubjectPermission, error) {
  4345  	subjects, err := parsePermSubjects(v, errors)
  4346  	if err != nil {
  4347  		return nil, err
  4348  	}
  4349  	return &SubjectPermission{Allow: subjects}, nil
  4350  }
  4351  
  4352  // Helper function to parse new style authorization into a SubjectPermission with Allow and Deny.
  4353  func parseSubjectPermission(v any, errors *[]error) (*SubjectPermission, error) {
  4354  	var lt token
  4355  	defer convertPanicToErrorList(&lt, errors)
  4356  
  4357  	m := v.(map[string]any)
  4358  	if len(m) == 0 {
  4359  		return nil, nil
  4360  	}
  4361  	p := &SubjectPermission{}
  4362  	for k, v := range m {
  4363  		tk, _ := unwrapValue(v, &lt)
  4364  		switch strings.ToLower(k) {
  4365  		case "allow":
  4366  			subjects, err := parsePermSubjects(tk, errors)
  4367  			if err != nil {
  4368  				*errors = append(*errors, err)
  4369  				continue
  4370  			}
  4371  			p.Allow = subjects
  4372  		case "deny":
  4373  			subjects, err := parsePermSubjects(tk, errors)
  4374  			if err != nil {
  4375  				*errors = append(*errors, err)
  4376  				continue
  4377  			}
  4378  			p.Deny = subjects
  4379  		default:
  4380  			if !tk.IsUsedVariable() {
  4381  				err := &configErr{tk, fmt.Sprintf("Unknown field name %q parsing subject permissions, only 'allow' or 'deny' are permitted", k)}
  4382  				*errors = append(*errors, err)
  4383  			}
  4384  		}
  4385  	}
  4386  	return p, nil
  4387  }
  4388  
  4389  // Helper function to validate permissions subjects.
  4390  func checkPermSubjectArray(sa []string) error {
  4391  	for _, s := range sa {
  4392  		if !IsValidSubject(s) {
  4393  			// Check here if this is a queue group qualified subject.
  4394  			elements := strings.Fields(s)
  4395  			if len(elements) != 2 {
  4396  				return fmt.Errorf("subject %q is not a valid subject", s)
  4397  			} else if !IsValidSubject(elements[0]) {
  4398  				return fmt.Errorf("subject %q is not a valid subject", elements[0])
  4399  			}
  4400  		}
  4401  	}
  4402  	return nil
  4403  }
  4404  
  4405  // PrintTLSHelpAndDie prints TLS usage and exits.
  4406  func PrintTLSHelpAndDie() {
  4407  	fmt.Printf("%s", tlsUsage)
  4408  	for k := range cipherMap {
  4409  		fmt.Printf("    %s\n", k)
  4410  	}
  4411  	fmt.Printf("\nAvailable curve preferences include:\n")
  4412  	for k := range curvePreferenceMap {
  4413  		fmt.Printf("    %s\n", k)
  4414  	}
  4415  	if runtime.GOOS == "windows" {
  4416  		fmt.Printf("%s\n", certstore.Usage)
  4417  	}
  4418  	fmt.Printf("%s", certidp.OCSPPeerUsage)
  4419  	fmt.Printf("%s", OCSPResponseCacheUsage)
  4420  	os.Exit(0)
  4421  }
  4422  
  4423  func parseCipher(cipherName string) (uint16, error) {
  4424  	cipher, exists := cipherMap[cipherName]
  4425  	if !exists {
  4426  		return 0, fmt.Errorf("unrecognized cipher %s", cipherName)
  4427  	}
  4428  
  4429  	return cipher, nil
  4430  }
  4431  
  4432  func parseCurvePreferences(curveName string) (tls.CurveID, error) {
  4433  	curve, exists := curvePreferenceMap[curveName]
  4434  	if !exists {
  4435  		return 0, fmt.Errorf("unrecognized curve preference %s", curveName)
  4436  	}
  4437  	return curve, nil
  4438  }
  4439  
  4440  // Helper function to parse TLS configs.
  4441  func parseTLS(v any, isClientCtx bool) (t *TLSConfigOpts, retErr error) {
  4442  	var (
  4443  		tlsm map[string]any
  4444  		tc   = TLSConfigOpts{}
  4445  		lt   token
  4446  	)
  4447  	defer convertPanicToError(&lt, &retErr)
  4448  
  4449  	tk, v := unwrapValue(v, &lt)
  4450  	tlsm = v.(map[string]any)
  4451  	for mk, mv := range tlsm {
  4452  		tk, mv := unwrapValue(mv, &lt)
  4453  		switch strings.ToLower(mk) {
  4454  		case "cert_file":
  4455  			certFile, ok := mv.(string)
  4456  			if !ok {
  4457  				return nil, &configErr{tk, "error parsing tls config, expected 'cert_file' to be filename"}
  4458  			}
  4459  			tc.CertFile = certFile
  4460  		case "key_file":
  4461  			keyFile, ok := mv.(string)
  4462  			if !ok {
  4463  				return nil, &configErr{tk, "error parsing tls config, expected 'key_file' to be filename"}
  4464  			}
  4465  			tc.KeyFile = keyFile
  4466  		case "ca_file":
  4467  			caFile, ok := mv.(string)
  4468  			if !ok {
  4469  				return nil, &configErr{tk, "error parsing tls config, expected 'ca_file' to be filename"}
  4470  			}
  4471  			tc.CaFile = caFile
  4472  		case "insecure":
  4473  			insecure, ok := mv.(bool)
  4474  			if !ok {
  4475  				return nil, &configErr{tk, "error parsing tls config, expected 'insecure' to be a boolean"}
  4476  			}
  4477  			tc.Insecure = insecure
  4478  		case "verify":
  4479  			verify, ok := mv.(bool)
  4480  			if !ok {
  4481  				return nil, &configErr{tk, "error parsing tls config, expected 'verify' to be a boolean"}
  4482  			}
  4483  			tc.Verify = verify
  4484  		case "verify_and_map":
  4485  			verify, ok := mv.(bool)
  4486  			if !ok {
  4487  				return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_map' to be a boolean"}
  4488  			}
  4489  			if verify {
  4490  				tc.Verify = verify
  4491  			}
  4492  			tc.Map = verify
  4493  		case "verify_cert_and_check_known_urls":
  4494  			verify, ok := mv.(bool)
  4495  			if !ok {
  4496  				return nil, &configErr{tk, "error parsing tls config, expected 'verify_cert_and_check_known_urls' to be a boolean"}
  4497  			}
  4498  			if verify && isClientCtx {
  4499  				return nil, &configErr{tk, "verify_cert_and_check_known_urls not supported in this context"}
  4500  			}
  4501  			if verify {
  4502  				tc.Verify = verify
  4503  			}
  4504  			tc.TLSCheckKnownURLs = verify
  4505  		case "cipher_suites":
  4506  			ra := mv.([]any)
  4507  			if len(ra) == 0 {
  4508  				return nil, &configErr{tk, "error parsing tls config, 'cipher_suites' cannot be empty"}
  4509  			}
  4510  			tc.Ciphers = make([]uint16, 0, len(ra))
  4511  			for _, r := range ra {
  4512  				tk, r := unwrapValue(r, &lt)
  4513  				cipher, err := parseCipher(r.(string))
  4514  				if err != nil {
  4515  					return nil, &configErr{tk, err.Error()}
  4516  				}
  4517  				tc.Ciphers = append(tc.Ciphers, cipher)
  4518  			}
  4519  		case "curve_preferences":
  4520  			ra := mv.([]any)
  4521  			if len(ra) == 0 {
  4522  				return nil, &configErr{tk, "error parsing tls config, 'curve_preferences' cannot be empty"}
  4523  			}
  4524  			tc.CurvePreferences = make([]tls.CurveID, 0, len(ra))
  4525  			for _, r := range ra {
  4526  				tk, r := unwrapValue(r, &lt)
  4527  				cps, err := parseCurvePreferences(r.(string))
  4528  				if err != nil {
  4529  					return nil, &configErr{tk, err.Error()}
  4530  				}
  4531  				tc.CurvePreferences = append(tc.CurvePreferences, cps)
  4532  			}
  4533  		case "timeout":
  4534  			at := float64(0)
  4535  			switch mv := mv.(type) {
  4536  			case int64:
  4537  				at = float64(mv)
  4538  			case float64:
  4539  				at = mv
  4540  			case string:
  4541  				d, err := time.ParseDuration(mv)
  4542  				if err != nil {
  4543  					return nil, &configErr{tk, fmt.Sprintf("error parsing tls config, 'timeout' %s", err)}
  4544  				}
  4545  				at = d.Seconds()
  4546  			default:
  4547  				return nil, &configErr{tk, "error parsing tls config, 'timeout' wrong type"}
  4548  			}
  4549  			tc.Timeout = at
  4550  		case "connection_rate_limit":
  4551  			at := int64(0)
  4552  			switch mv := mv.(type) {
  4553  			case int64:
  4554  				at = mv
  4555  			default:
  4556  				return nil, &configErr{tk, "error parsing tls config, 'connection_rate_limit' wrong type"}
  4557  			}
  4558  			tc.RateLimit = at
  4559  		case "pinned_certs":
  4560  			ra, ok := mv.([]any)
  4561  			if !ok {
  4562  				return nil, &configErr{tk, "error parsing tls config, expected 'pinned_certs' to be a list of hex-encoded sha256 of DER encoded SubjectPublicKeyInfo"}
  4563  			}
  4564  			if len(ra) != 0 {
  4565  				wl := PinnedCertSet{}
  4566  				re := regexp.MustCompile("^[A-Fa-f0-9]{64}$")
  4567  				for _, r := range ra {
  4568  					tk, r := unwrapValue(r, &lt)
  4569  					entry := strings.ToLower(r.(string))
  4570  					if !re.MatchString(entry) {
  4571  						return nil, &configErr{tk, fmt.Sprintf("error parsing tls config, 'pinned_certs' key %s does not look like hex-encoded sha256 of DER encoded SubjectPublicKeyInfo", entry)}
  4572  					}
  4573  					wl[entry] = struct{}{}
  4574  				}
  4575  				tc.PinnedCerts = wl
  4576  			}
  4577  		case "cert_store":
  4578  			certStore, ok := mv.(string)
  4579  			if !ok || certStore == _EMPTY_ {
  4580  				return nil, &configErr{tk, certstore.ErrBadCertStoreField.Error()}
  4581  			}
  4582  			certStoreType, err := certstore.ParseCertStore(certStore)
  4583  			if err != nil {
  4584  				return nil, &configErr{tk, err.Error()}
  4585  			}
  4586  			tc.CertStore = certStoreType
  4587  		case "cert_match_by":
  4588  			certMatchBy, ok := mv.(string)
  4589  			if !ok || certMatchBy == _EMPTY_ {
  4590  				return nil, &configErr{tk, certstore.ErrBadCertMatchByField.Error()}
  4591  			}
  4592  			certMatchByType, err := certstore.ParseCertMatchBy(certMatchBy)
  4593  			if err != nil {
  4594  				return nil, &configErr{tk, err.Error()}
  4595  			}
  4596  			tc.CertMatchBy = certMatchByType
  4597  		case "cert_match":
  4598  			certMatch, ok := mv.(string)
  4599  			if !ok || certMatch == _EMPTY_ {
  4600  				return nil, &configErr{tk, certstore.ErrBadCertMatchField.Error()}
  4601  			}
  4602  			tc.CertMatch = certMatch
  4603  		case "ca_certs_match":
  4604  			rv := []string{}
  4605  			switch mv := mv.(type) {
  4606  			case string:
  4607  				rv = append(rv, mv)
  4608  			case []string:
  4609  				rv = append(rv, mv...)
  4610  			case []any:
  4611  				for _, t := range mv {
  4612  					if token, ok := t.(token); ok {
  4613  						if ts, ok := token.Value().(string); ok {
  4614  							rv = append(rv, ts)
  4615  							continue
  4616  						} else {
  4617  							return nil, &configErr{tk, fmt.Sprintf("error parsing ca_cert_match: unsupported type %T where string is expected", token)}
  4618  						}
  4619  					} else {
  4620  						return nil, &configErr{tk, fmt.Sprintf("error parsing ca_cert_match: unsupported type %T", t)}
  4621  					}
  4622  				}
  4623  			}
  4624  			tc.CaCertsMatch = rv
  4625  		case "handshake_first", "first", "immediate":
  4626  			switch mv := mv.(type) {
  4627  			case bool:
  4628  				tc.HandshakeFirst = mv
  4629  			case string:
  4630  				switch strings.ToLower(mv) {
  4631  				case "true", "on":
  4632  					tc.HandshakeFirst = true
  4633  				case "false", "off":
  4634  					tc.HandshakeFirst = false
  4635  				case "auto", "auto_fallback":
  4636  					tc.HandshakeFirst = true
  4637  					tc.FallbackDelay = DEFAULT_TLS_HANDSHAKE_FIRST_FALLBACK_DELAY
  4638  				default:
  4639  					// Check to see if this is a duration.
  4640  					if dur, err := time.ParseDuration(mv); err == nil {
  4641  						tc.HandshakeFirst = true
  4642  						tc.FallbackDelay = dur
  4643  						break
  4644  					}
  4645  					return nil, &configErr{tk, fmt.Sprintf("field %q's value %q is invalid", mk, mv)}
  4646  				}
  4647  			default:
  4648  				return nil, &configErr{tk, fmt.Sprintf("field %q should be a boolean or a string, got %T", mk, mv)}
  4649  			}
  4650  		case "ocsp_peer":
  4651  			switch vv := mv.(type) {
  4652  			case bool:
  4653  				pc := certidp.NewOCSPPeerConfig()
  4654  				if vv {
  4655  					// Set enabled
  4656  					pc.Verify = true
  4657  					tc.OCSPPeerConfig = pc
  4658  				} else {
  4659  					// Set disabled
  4660  					pc.Verify = false
  4661  					tc.OCSPPeerConfig = pc
  4662  				}
  4663  			case map[string]any:
  4664  				pc, err := parseOCSPPeer(mv)
  4665  				if err != nil {
  4666  					return nil, &configErr{tk, err.Error()}
  4667  				}
  4668  				tc.OCSPPeerConfig = pc
  4669  			default:
  4670  				return nil, &configErr{tk, fmt.Sprintf("error parsing ocsp peer config: unsupported type %T", v)}
  4671  			}
  4672  		case "certs", "certificates":
  4673  			certs, ok := mv.([]any)
  4674  			if !ok {
  4675  				return nil, &configErr{tk, fmt.Sprintf("error parsing certificates config: unsupported type %T", v)}
  4676  			}
  4677  			tc.Certificates = make([]*TLSCertPairOpt, len(certs))
  4678  			for i, v := range certs {
  4679  				tk, vv := unwrapValue(v, &lt)
  4680  				pair, ok := vv.(map[string]any)
  4681  				if !ok {
  4682  					return nil, &configErr{tk, fmt.Sprintf("error parsing certificates config: unsupported type %T", vv)}
  4683  				}
  4684  				certPair := &TLSCertPairOpt{}
  4685  				for k, v := range pair {
  4686  					tk, vv = unwrapValue(v, &lt)
  4687  					file, ok := vv.(string)
  4688  					if !ok {
  4689  						return nil, &configErr{tk, fmt.Sprintf("error parsing certificates config: unsupported type %T", vv)}
  4690  					}
  4691  					switch k {
  4692  					case "cert_file":
  4693  						certPair.CertFile = file
  4694  					case "key_file":
  4695  						certPair.KeyFile = file
  4696  					default:
  4697  						return nil, &configErr{tk, fmt.Sprintf("error parsing tls certs config, unknown field %q", k)}
  4698  					}
  4699  				}
  4700  				if certPair.CertFile == _EMPTY_ || certPair.KeyFile == _EMPTY_ {
  4701  					return nil, &configErr{tk, "error parsing certificates config: both 'cert_file' and 'cert_key' options are required"}
  4702  				}
  4703  				tc.Certificates[i] = certPair
  4704  			}
  4705  		default:
  4706  			return nil, &configErr{tk, fmt.Sprintf("error parsing tls config, unknown field %q", mk)}
  4707  		}
  4708  	}
  4709  	if len(tc.Certificates) > 0 && tc.CertFile != _EMPTY_ {
  4710  		return nil, &configErr{tk, "error parsing tls config, cannot combine 'cert_file' option with 'certs' option"}
  4711  	}
  4712  
  4713  	// If cipher suites were not specified then use the defaults
  4714  	if tc.Ciphers == nil {
  4715  		tc.Ciphers = defaultCipherSuites()
  4716  	}
  4717  
  4718  	// If curve preferences were not specified, then use the defaults
  4719  	if tc.CurvePreferences == nil {
  4720  		tc.CurvePreferences = defaultCurvePreferences()
  4721  	}
  4722  
  4723  	return &tc, nil
  4724  }
  4725  
  4726  func parseSimpleAuth(v any, errors *[]error) *authorization {
  4727  	var (
  4728  		am   map[string]any
  4729  		tk   token
  4730  		lt   token
  4731  		auth = &authorization{}
  4732  	)
  4733  	defer convertPanicToErrorList(&lt, errors)
  4734  
  4735  	_, v = unwrapValue(v, &lt)
  4736  	am = v.(map[string]any)
  4737  	for mk, mv := range am {
  4738  		tk, mv = unwrapValue(mv, &lt)
  4739  		switch strings.ToLower(mk) {
  4740  		case "user", "username":
  4741  			auth.user = mv.(string)
  4742  		case "pass", "password":
  4743  			auth.pass = mv.(string)
  4744  		case "token":
  4745  			auth.token = mv.(string)
  4746  		case "timeout":
  4747  			at := float64(1)
  4748  			switch mv := mv.(type) {
  4749  			case int64:
  4750  				at = float64(mv)
  4751  			case float64:
  4752  				at = mv
  4753  			}
  4754  			auth.timeout = at
  4755  		default:
  4756  			if !tk.IsUsedVariable() {
  4757  				err := &unknownConfigFieldErr{
  4758  					field: mk,
  4759  					configErr: configErr{
  4760  						token: tk,
  4761  					},
  4762  				}
  4763  				*errors = append(*errors, err)
  4764  			}
  4765  			continue
  4766  		}
  4767  	}
  4768  	return auth
  4769  }
  4770  
  4771  func parseStringArray(fieldName string, tk token, lt *token, mv any, errors *[]error) ([]string, error) {
  4772  	switch mv := mv.(type) {
  4773  	case string:
  4774  		return []string{mv}, nil
  4775  	case []any:
  4776  		strs := make([]string, 0, len(mv))
  4777  		for _, val := range mv {
  4778  			tk, val = unwrapValue(val, lt)
  4779  			if str, ok := val.(string); ok {
  4780  				strs = append(strs, str)
  4781  			} else {
  4782  				err := &configErr{tk, fmt.Sprintf("error parsing %s: unsupported type in array %T", fieldName, val)}
  4783  				*errors = append(*errors, err)
  4784  				continue
  4785  			}
  4786  		}
  4787  		return strs, nil
  4788  	default:
  4789  		err := &configErr{tk, fmt.Sprintf("error parsing %s: unsupported type %T", fieldName, mv)}
  4790  		*errors = append(*errors, err)
  4791  		return nil, err
  4792  	}
  4793  }
  4794  
  4795  func parseWebsocket(v any, o *Options, errors *[]error) error {
  4796  	var lt token
  4797  	defer convertPanicToErrorList(&lt, errors)
  4798  
  4799  	tk, v := unwrapValue(v, &lt)
  4800  	gm, ok := v.(map[string]any)
  4801  	if !ok {
  4802  		return &configErr{tk, fmt.Sprintf("Expected websocket to be a map, got %T", v)}
  4803  	}
  4804  	for mk, mv := range gm {
  4805  		// Again, unwrap token value if line check is required.
  4806  		tk, mv = unwrapValue(mv, &lt)
  4807  		switch strings.ToLower(mk) {
  4808  		case "listen":
  4809  			hp, err := parseListen(mv)
  4810  			if err != nil {
  4811  				err := &configErr{tk, err.Error()}
  4812  				*errors = append(*errors, err)
  4813  				continue
  4814  			}
  4815  			o.Websocket.Host = hp.host
  4816  			o.Websocket.Port = hp.port
  4817  		case "port":
  4818  			o.Websocket.Port = int(mv.(int64))
  4819  		case "host", "net":
  4820  			o.Websocket.Host = mv.(string)
  4821  		case "advertise":
  4822  			o.Websocket.Advertise = mv.(string)
  4823  		case "no_tls":
  4824  			o.Websocket.NoTLS = mv.(bool)
  4825  		case "tls":
  4826  			tc, err := parseTLS(tk, true)
  4827  			if err != nil {
  4828  				*errors = append(*errors, err)
  4829  				continue
  4830  			}
  4831  			if o.Websocket.TLSConfig, err = GenTLSConfig(tc); err != nil {
  4832  				err := &configErr{tk, err.Error()}
  4833  				*errors = append(*errors, err)
  4834  				continue
  4835  			}
  4836  			o.Websocket.TLSMap = tc.Map
  4837  			o.Websocket.TLSPinnedCerts = tc.PinnedCerts
  4838  			o.Websocket.tlsConfigOpts = tc
  4839  		case "same_origin":
  4840  			o.Websocket.SameOrigin = mv.(bool)
  4841  		case "allowed_origins", "allowed_origin", "allow_origins", "allow_origin", "origins", "origin":
  4842  			o.Websocket.AllowedOrigins, _ = parseStringArray("allowed origins", tk, &lt, mv, errors)
  4843  		case "handshake_timeout":
  4844  			ht := time.Duration(0)
  4845  			switch mv := mv.(type) {
  4846  			case int64:
  4847  				ht = time.Duration(mv) * time.Second
  4848  			case string:
  4849  				var err error
  4850  				ht, err = time.ParseDuration(mv)
  4851  				if err != nil {
  4852  					err := &configErr{tk, err.Error()}
  4853  					*errors = append(*errors, err)
  4854  					continue
  4855  				}
  4856  			default:
  4857  				err := &configErr{tk, fmt.Sprintf("error parsing handshake timeout: unsupported type %T", mv)}
  4858  				*errors = append(*errors, err)
  4859  			}
  4860  			o.Websocket.HandshakeTimeout = ht
  4861  		case "compress", "compression":
  4862  			o.Websocket.Compression = mv.(bool)
  4863  		case "authorization", "authentication":
  4864  			auth := parseSimpleAuth(tk, errors)
  4865  			o.Websocket.Username = auth.user
  4866  			o.Websocket.Password = auth.pass
  4867  			o.Websocket.Token = auth.token
  4868  			o.Websocket.AuthTimeout = auth.timeout
  4869  		case "jwt_cookie":
  4870  			o.Websocket.JWTCookie = mv.(string)
  4871  		case "user_cookie":
  4872  			o.Websocket.UsernameCookie = mv.(string)
  4873  		case "pass_cookie":
  4874  			o.Websocket.PasswordCookie = mv.(string)
  4875  		case "token_cookie":
  4876  			o.Websocket.TokenCookie = mv.(string)
  4877  		case "no_auth_user":
  4878  			o.Websocket.NoAuthUser = mv.(string)
  4879  		case "headers":
  4880  			m, ok := mv.(map[string]any)
  4881  			if !ok {
  4882  				err := &configErr{tk, fmt.Sprintf("error parsing headers: unsupported type %T", mv)}
  4883  				*errors = append(*errors, err)
  4884  				continue
  4885  			}
  4886  			o.Websocket.Headers = make(map[string]string)
  4887  			for key, val := range m {
  4888  				tk, val = unwrapValue(val, &lt)
  4889  				if headerValue, ok := val.(string); !ok {
  4890  					*errors = append(*errors, &configErr{tk, fmt.Sprintf("error parsing header key %s: unsupported type %T", key, val)})
  4891  					continue
  4892  				} else {
  4893  					o.Websocket.Headers[key] = headerValue
  4894  				}
  4895  			}
  4896  		default:
  4897  			if !tk.IsUsedVariable() {
  4898  				err := &unknownConfigFieldErr{
  4899  					field: mk,
  4900  					configErr: configErr{
  4901  						token: tk,
  4902  					},
  4903  				}
  4904  				*errors = append(*errors, err)
  4905  				continue
  4906  			}
  4907  		}
  4908  	}
  4909  	return nil
  4910  }
  4911  
  4912  func parseMQTT(v any, o *Options, errors *[]error, warnings *[]error) error {
  4913  	var lt token
  4914  	defer convertPanicToErrorList(&lt, errors)
  4915  
  4916  	tk, v := unwrapValue(v, &lt)
  4917  	gm, ok := v.(map[string]any)
  4918  	if !ok {
  4919  		return &configErr{tk, fmt.Sprintf("Expected mqtt to be a map, got %T", v)}
  4920  	}
  4921  	for mk, mv := range gm {
  4922  		// Again, unwrap token value if line check is required.
  4923  		tk, mv = unwrapValue(mv, &lt)
  4924  		switch strings.ToLower(mk) {
  4925  		case "listen":
  4926  			hp, err := parseListen(mv)
  4927  			if err != nil {
  4928  				err := &configErr{tk, err.Error()}
  4929  				*errors = append(*errors, err)
  4930  				continue
  4931  			}
  4932  			o.MQTT.Host = hp.host
  4933  			o.MQTT.Port = hp.port
  4934  		case "port":
  4935  			o.MQTT.Port = int(mv.(int64))
  4936  		case "host", "net":
  4937  			o.MQTT.Host = mv.(string)
  4938  		case "tls":
  4939  			tc, err := parseTLS(tk, true)
  4940  			if err != nil {
  4941  				*errors = append(*errors, err)
  4942  				continue
  4943  			}
  4944  			if o.MQTT.TLSConfig, err = GenTLSConfig(tc); err != nil {
  4945  				err := &configErr{tk, err.Error()}
  4946  				*errors = append(*errors, err)
  4947  				continue
  4948  			}
  4949  			o.MQTT.TLSTimeout = tc.Timeout
  4950  			o.MQTT.TLSMap = tc.Map
  4951  			o.MQTT.TLSPinnedCerts = tc.PinnedCerts
  4952  			o.MQTT.tlsConfigOpts = tc
  4953  		case "authorization", "authentication":
  4954  			auth := parseSimpleAuth(tk, errors)
  4955  			o.MQTT.Username = auth.user
  4956  			o.MQTT.Password = auth.pass
  4957  			o.MQTT.Token = auth.token
  4958  			o.MQTT.AuthTimeout = auth.timeout
  4959  		case "no_auth_user":
  4960  			o.MQTT.NoAuthUser = mv.(string)
  4961  		case "ack_wait", "ackwait":
  4962  			o.MQTT.AckWait = parseDuration("ack_wait", tk, mv, errors, warnings)
  4963  		case "max_ack_pending", "max_pending", "max_inflight":
  4964  			tmp := int(mv.(int64))
  4965  			if tmp < 0 || tmp > 0xFFFF {
  4966  				err := &configErr{tk, fmt.Sprintf("invalid value %v, should in [0..%d] range", tmp, 0xFFFF)}
  4967  				*errors = append(*errors, err)
  4968  			} else {
  4969  				o.MQTT.MaxAckPending = uint16(tmp)
  4970  			}
  4971  		case "js_domain":
  4972  			o.MQTT.JsDomain = mv.(string)
  4973  		case "stream_replicas":
  4974  			o.MQTT.StreamReplicas = int(mv.(int64))
  4975  		case "consumer_replicas":
  4976  			err := &configWarningErr{
  4977  				field: mk,
  4978  				configErr: configErr{
  4979  					token:  tk,
  4980  					reason: `consumer replicas setting ignored in this server version`,
  4981  				},
  4982  			}
  4983  			*warnings = append(*warnings, err)
  4984  		case "consumer_memory_storage":
  4985  			o.MQTT.ConsumerMemoryStorage = mv.(bool)
  4986  		case "consumer_inactive_threshold", "consumer_auto_cleanup":
  4987  			o.MQTT.ConsumerInactiveThreshold = parseDuration("consumer_inactive_threshold", tk, mv, errors, warnings)
  4988  
  4989  		case "reject_qos2_publish":
  4990  			o.MQTT.rejectQoS2Pub = mv.(bool)
  4991  		case "downgrade_qos2_subscribe":
  4992  			o.MQTT.downgradeQoS2Sub = mv.(bool)
  4993  
  4994  		default:
  4995  			if !tk.IsUsedVariable() {
  4996  				err := &unknownConfigFieldErr{
  4997  					field: mk,
  4998  					configErr: configErr{
  4999  						token: tk,
  5000  					},
  5001  				}
  5002  				*errors = append(*errors, err)
  5003  				continue
  5004  			}
  5005  		}
  5006  	}
  5007  	return nil
  5008  }
  5009  
  5010  // GenTLSConfig loads TLS related configuration parameters.
  5011  func GenTLSConfig(tc *TLSConfigOpts) (*tls.Config, error) {
  5012  	// Create the tls.Config from our options before including the certs.
  5013  	// It will determine the cipher suites that we prefer.
  5014  	// FIXME(dlc) change if ARM based.
  5015  	config := tls.Config{
  5016  		MinVersion:               tls.VersionTLS12,
  5017  		CipherSuites:             tc.Ciphers,
  5018  		PreferServerCipherSuites: true,
  5019  		CurvePreferences:         tc.CurvePreferences,
  5020  		InsecureSkipVerify:       tc.Insecure,
  5021  	}
  5022  
  5023  	switch {
  5024  	case tc.CertFile != _EMPTY_ && tc.CertStore != certstore.STOREEMPTY:
  5025  		return nil, certstore.ErrConflictCertFileAndStore
  5026  	case tc.CertFile != _EMPTY_ && tc.KeyFile == _EMPTY_:
  5027  		return nil, fmt.Errorf("missing 'key_file' in TLS configuration")
  5028  	case tc.CertFile == _EMPTY_ && tc.KeyFile != _EMPTY_:
  5029  		return nil, fmt.Errorf("missing 'cert_file' in TLS configuration")
  5030  	case tc.CertFile != _EMPTY_ && tc.KeyFile != _EMPTY_:
  5031  		// Now load in cert and private key
  5032  		cert, err := tls.LoadX509KeyPair(tc.CertFile, tc.KeyFile)
  5033  		if err != nil {
  5034  			return nil, fmt.Errorf("error parsing X509 certificate/key pair: %v", err)
  5035  		}
  5036  		cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
  5037  		if err != nil {
  5038  			return nil, fmt.Errorf("error parsing certificate: %v", err)
  5039  		}
  5040  		config.Certificates = []tls.Certificate{cert}
  5041  	case tc.CertStore != certstore.STOREEMPTY:
  5042  		err := certstore.TLSConfig(tc.CertStore, tc.CertMatchBy, tc.CertMatch, tc.CaCertsMatch, &config)
  5043  		if err != nil {
  5044  			return nil, err
  5045  		}
  5046  	case tc.Certificates != nil:
  5047  		// Multiple certificate support.
  5048  		config.Certificates = make([]tls.Certificate, len(tc.Certificates))
  5049  		for i, certPair := range tc.Certificates {
  5050  			cert, err := tls.LoadX509KeyPair(certPair.CertFile, certPair.KeyFile)
  5051  			if err != nil {
  5052  				return nil, fmt.Errorf("error parsing X509 certificate/key pair %d/%d: %v", i+1, len(tc.Certificates), err)
  5053  			}
  5054  			cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
  5055  			if err != nil {
  5056  				return nil, fmt.Errorf("error parsing certificate %d/%d: %v", i+1, len(tc.Certificates), err)
  5057  			}
  5058  			config.Certificates[i] = cert
  5059  		}
  5060  	}
  5061  
  5062  	// Require client certificates as needed
  5063  	if tc.Verify {
  5064  		config.ClientAuth = tls.RequireAndVerifyClientCert
  5065  	}
  5066  	// Add in CAs if applicable.
  5067  	if tc.CaFile != _EMPTY_ {
  5068  		rootPEM, err := os.ReadFile(tc.CaFile)
  5069  		if err != nil || rootPEM == nil {
  5070  			return nil, err
  5071  		}
  5072  		pool := x509.NewCertPool()
  5073  		ok := pool.AppendCertsFromPEM(rootPEM)
  5074  		if !ok {
  5075  			return nil, fmt.Errorf("failed to parse root ca certificate")
  5076  		}
  5077  		config.ClientCAs = pool
  5078  	}
  5079  
  5080  	return &config, nil
  5081  }
  5082  
  5083  // MergeOptions will merge two options giving preference to the flagOpts
  5084  // if the item is present.
  5085  func MergeOptions(fileOpts, flagOpts *Options) *Options {
  5086  	if fileOpts == nil {
  5087  		return flagOpts
  5088  	}
  5089  	if flagOpts == nil {
  5090  		return fileOpts
  5091  	}
  5092  	// Merge the two, flagOpts override
  5093  	opts := *fileOpts
  5094  
  5095  	if flagOpts.Port != 0 {
  5096  		opts.Port = flagOpts.Port
  5097  	}
  5098  	if flagOpts.Host != _EMPTY_ {
  5099  		opts.Host = flagOpts.Host
  5100  	}
  5101  	if flagOpts.DontListen {
  5102  		opts.DontListen = flagOpts.DontListen
  5103  	}
  5104  	if flagOpts.ClientAdvertise != _EMPTY_ {
  5105  		opts.ClientAdvertise = flagOpts.ClientAdvertise
  5106  	}
  5107  	if flagOpts.Username != _EMPTY_ {
  5108  		opts.Username = flagOpts.Username
  5109  	}
  5110  	if flagOpts.Password != _EMPTY_ {
  5111  		opts.Password = flagOpts.Password
  5112  	}
  5113  	if flagOpts.Authorization != _EMPTY_ {
  5114  		opts.Authorization = flagOpts.Authorization
  5115  	}
  5116  	if flagOpts.HTTPPort != 0 {
  5117  		opts.HTTPPort = flagOpts.HTTPPort
  5118  	}
  5119  	if flagOpts.HTTPBasePath != _EMPTY_ {
  5120  		opts.HTTPBasePath = flagOpts.HTTPBasePath
  5121  	}
  5122  	if flagOpts.Debug {
  5123  		opts.Debug = true
  5124  	}
  5125  	if flagOpts.Trace {
  5126  		opts.Trace = true
  5127  	}
  5128  	if flagOpts.Logtime {
  5129  		opts.Logtime = true
  5130  	}
  5131  	if flagOpts.LogFile != _EMPTY_ {
  5132  		opts.LogFile = flagOpts.LogFile
  5133  	}
  5134  	if flagOpts.PidFile != _EMPTY_ {
  5135  		opts.PidFile = flagOpts.PidFile
  5136  	}
  5137  	if flagOpts.PortsFileDir != _EMPTY_ {
  5138  		opts.PortsFileDir = flagOpts.PortsFileDir
  5139  	}
  5140  	if flagOpts.ProfPort != 0 {
  5141  		opts.ProfPort = flagOpts.ProfPort
  5142  	}
  5143  	if flagOpts.Cluster.ListenStr != _EMPTY_ {
  5144  		opts.Cluster.ListenStr = flagOpts.Cluster.ListenStr
  5145  	}
  5146  	if flagOpts.Cluster.NoAdvertise {
  5147  		opts.Cluster.NoAdvertise = true
  5148  	}
  5149  	if flagOpts.Cluster.ConnectRetries != 0 {
  5150  		opts.Cluster.ConnectRetries = flagOpts.Cluster.ConnectRetries
  5151  	}
  5152  	if flagOpts.Cluster.Advertise != _EMPTY_ {
  5153  		opts.Cluster.Advertise = flagOpts.Cluster.Advertise
  5154  	}
  5155  	if flagOpts.RoutesStr != _EMPTY_ {
  5156  		mergeRoutes(&opts, flagOpts)
  5157  	}
  5158  	if flagOpts.JetStream {
  5159  		fileOpts.JetStream = flagOpts.JetStream
  5160  	}
  5161  	return &opts
  5162  }
  5163  
  5164  // RoutesFromStr parses route URLs from a string
  5165  func RoutesFromStr(routesStr string) []*url.URL {
  5166  	routes := strings.Split(routesStr, ",")
  5167  	if len(routes) == 0 {
  5168  		return nil
  5169  	}
  5170  	routeUrls := []*url.URL{}
  5171  	for _, r := range routes {
  5172  		r = strings.TrimSpace(r)
  5173  		u, _ := url.Parse(r)
  5174  		routeUrls = append(routeUrls, u)
  5175  	}
  5176  	return routeUrls
  5177  }
  5178  
  5179  // This will merge the flag routes and override anything that was present.
  5180  func mergeRoutes(opts, flagOpts *Options) {
  5181  	routeUrls := RoutesFromStr(flagOpts.RoutesStr)
  5182  	if routeUrls == nil {
  5183  		return
  5184  	}
  5185  	opts.Routes = routeUrls
  5186  	opts.RoutesStr = flagOpts.RoutesStr
  5187  }
  5188  
  5189  // RemoveSelfReference removes this server from an array of routes
  5190  func RemoveSelfReference(clusterPort int, routes []*url.URL) ([]*url.URL, error) {
  5191  	var cleanRoutes []*url.URL
  5192  	cport := strconv.Itoa(clusterPort)
  5193  
  5194  	selfIPs, err := getInterfaceIPs()
  5195  	if err != nil {
  5196  		return nil, err
  5197  	}
  5198  	for _, r := range routes {
  5199  		host, port, err := net.SplitHostPort(r.Host)
  5200  		if err != nil {
  5201  			return nil, err
  5202  		}
  5203  
  5204  		ipList, err := getURLIP(host)
  5205  		if err != nil {
  5206  			return nil, err
  5207  		}
  5208  		if cport == port && isIPInList(selfIPs, ipList) {
  5209  			continue
  5210  		}
  5211  		cleanRoutes = append(cleanRoutes, r)
  5212  	}
  5213  
  5214  	return cleanRoutes, nil
  5215  }
  5216  
  5217  func isIPInList(list1 []net.IP, list2 []net.IP) bool {
  5218  	for _, ip1 := range list1 {
  5219  		for _, ip2 := range list2 {
  5220  			if ip1.Equal(ip2) {
  5221  				return true
  5222  			}
  5223  		}
  5224  	}
  5225  	return false
  5226  }
  5227  
  5228  func getURLIP(ipStr string) ([]net.IP, error) {
  5229  	ipList := []net.IP{}
  5230  
  5231  	ip := net.ParseIP(ipStr)
  5232  	if ip != nil {
  5233  		ipList = append(ipList, ip)
  5234  		return ipList, nil
  5235  	}
  5236  
  5237  	hostAddr, err := net.LookupHost(ipStr)
  5238  	if err != nil {
  5239  		return nil, fmt.Errorf("Error looking up host with route hostname: %v", err)
  5240  	}
  5241  	for _, addr := range hostAddr {
  5242  		ip = net.ParseIP(addr)
  5243  		if ip != nil {
  5244  			ipList = append(ipList, ip)
  5245  		}
  5246  	}
  5247  	return ipList, nil
  5248  }
  5249  
  5250  func getInterfaceIPs() ([]net.IP, error) {
  5251  	var localIPs []net.IP
  5252  
  5253  	interfaceAddr, err := net.InterfaceAddrs()
  5254  	if err != nil {
  5255  		return nil, fmt.Errorf("Error getting self referencing address: %v", err)
  5256  	}
  5257  
  5258  	for i := 0; i < len(interfaceAddr); i++ {
  5259  		interfaceIP, _, _ := net.ParseCIDR(interfaceAddr[i].String())
  5260  		if net.ParseIP(interfaceIP.String()) != nil {
  5261  			localIPs = append(localIPs, interfaceIP)
  5262  		} else {
  5263  			return nil, fmt.Errorf("Error parsing self referencing address: %v", err)
  5264  		}
  5265  	}
  5266  	return localIPs, nil
  5267  }
  5268  
  5269  func setBaselineOptions(opts *Options) {
  5270  	// Setup non-standard Go defaults
  5271  	if opts.Host == _EMPTY_ {
  5272  		opts.Host = DEFAULT_HOST
  5273  	}
  5274  	if opts.HTTPHost == _EMPTY_ {
  5275  		// Default to same bind from server if left undefined
  5276  		opts.HTTPHost = opts.Host
  5277  	}
  5278  	if opts.Port == 0 {
  5279  		opts.Port = DEFAULT_PORT
  5280  	} else if opts.Port == RANDOM_PORT {
  5281  		// Choose randomly inside of net.Listen
  5282  		opts.Port = 0
  5283  	}
  5284  	if opts.MaxConn == 0 {
  5285  		opts.MaxConn = DEFAULT_MAX_CONNECTIONS
  5286  	}
  5287  	if opts.PingInterval == 0 {
  5288  		opts.PingInterval = DEFAULT_PING_INTERVAL
  5289  	}
  5290  	if opts.MaxPingsOut == 0 {
  5291  		opts.MaxPingsOut = DEFAULT_PING_MAX_OUT
  5292  	}
  5293  	if opts.TLSTimeout == 0 {
  5294  		opts.TLSTimeout = float64(TLS_TIMEOUT) / float64(time.Second)
  5295  	}
  5296  	if opts.AuthTimeout == 0 {
  5297  		opts.AuthTimeout = getDefaultAuthTimeout(opts.TLSConfig, opts.TLSTimeout)
  5298  	}
  5299  	if opts.Cluster.Port != 0 || opts.Cluster.ListenStr != _EMPTY_ {
  5300  		if opts.Cluster.Host == _EMPTY_ {
  5301  			opts.Cluster.Host = DEFAULT_HOST
  5302  		}
  5303  		if opts.Cluster.TLSTimeout == 0 {
  5304  			opts.Cluster.TLSTimeout = float64(TLS_TIMEOUT) / float64(time.Second)
  5305  		}
  5306  		if opts.Cluster.AuthTimeout == 0 {
  5307  			opts.Cluster.AuthTimeout = getDefaultAuthTimeout(opts.Cluster.TLSConfig, opts.Cluster.TLSTimeout)
  5308  		}
  5309  		if opts.Cluster.PoolSize == 0 {
  5310  			opts.Cluster.PoolSize = DEFAULT_ROUTE_POOL_SIZE
  5311  		}
  5312  		// Unless pooling/accounts are disabled (by PoolSize being set to -1),
  5313  		// check for Cluster.Accounts. Add the system account if not present and
  5314  		// unless we have a configuration that disabled it.
  5315  		if opts.Cluster.PoolSize > 0 {
  5316  			sysAccName := opts.SystemAccount
  5317  			if sysAccName == _EMPTY_ && !opts.NoSystemAccount {
  5318  				sysAccName = DEFAULT_SYSTEM_ACCOUNT
  5319  			}
  5320  			if sysAccName != _EMPTY_ {
  5321  				var found bool
  5322  				for _, acc := range opts.Cluster.PinnedAccounts {
  5323  					if acc == sysAccName {
  5324  						found = true
  5325  						break
  5326  					}
  5327  				}
  5328  				if !found {
  5329  					opts.Cluster.PinnedAccounts = append(opts.Cluster.PinnedAccounts, sysAccName)
  5330  				}
  5331  			}
  5332  		}
  5333  		// Default to compression "accept", which means that compression is not
  5334  		// initiated, but if the remote selects compression, this server will
  5335  		// use the same.
  5336  		if c := &opts.Cluster.Compression; c.Mode == _EMPTY_ {
  5337  			if testDefaultClusterCompression != _EMPTY_ {
  5338  				c.Mode = testDefaultClusterCompression
  5339  			} else {
  5340  				c.Mode = CompressionAccept
  5341  			}
  5342  		}
  5343  	}
  5344  	if opts.LeafNode.Port != 0 {
  5345  		if opts.LeafNode.Host == _EMPTY_ {
  5346  			opts.LeafNode.Host = DEFAULT_HOST
  5347  		}
  5348  		if opts.LeafNode.TLSTimeout == 0 {
  5349  			opts.LeafNode.TLSTimeout = float64(TLS_TIMEOUT) / float64(time.Second)
  5350  		}
  5351  		if opts.LeafNode.AuthTimeout == 0 {
  5352  			opts.LeafNode.AuthTimeout = getDefaultAuthTimeout(opts.LeafNode.TLSConfig, opts.LeafNode.TLSTimeout)
  5353  		}
  5354  		// Default to compression "s2_auto".
  5355  		if c := &opts.LeafNode.Compression; c.Mode == _EMPTY_ {
  5356  			if testDefaultLeafNodeCompression != _EMPTY_ {
  5357  				c.Mode = testDefaultLeafNodeCompression
  5358  			} else {
  5359  				c.Mode = CompressionS2Auto
  5360  			}
  5361  		}
  5362  	}
  5363  	// Set baseline connect port for remotes.
  5364  	for _, r := range opts.LeafNode.Remotes {
  5365  		if r != nil {
  5366  			for _, u := range r.URLs {
  5367  				if u.Port() == _EMPTY_ {
  5368  					u.Host = net.JoinHostPort(u.Host, strconv.Itoa(DEFAULT_LEAFNODE_PORT))
  5369  				}
  5370  			}
  5371  			// Default to compression "s2_auto".
  5372  			if c := &r.Compression; c.Mode == _EMPTY_ {
  5373  				if testDefaultLeafNodeCompression != _EMPTY_ {
  5374  					c.Mode = testDefaultLeafNodeCompression
  5375  				} else {
  5376  					c.Mode = CompressionS2Auto
  5377  				}
  5378  			}
  5379  		}
  5380  	}
  5381  
  5382  	// Set this regardless of opts.LeafNode.Port
  5383  	if opts.LeafNode.ReconnectInterval == 0 {
  5384  		opts.LeafNode.ReconnectInterval = DEFAULT_LEAF_NODE_RECONNECT
  5385  	}
  5386  
  5387  	if opts.MaxControlLine == 0 {
  5388  		opts.MaxControlLine = MAX_CONTROL_LINE_SIZE
  5389  	}
  5390  	if opts.MaxPayload == 0 {
  5391  		opts.MaxPayload = MAX_PAYLOAD_SIZE
  5392  	}
  5393  	if opts.MaxPending == 0 {
  5394  		opts.MaxPending = MAX_PENDING_SIZE
  5395  	}
  5396  	if opts.WriteDeadline == time.Duration(0) {
  5397  		opts.WriteDeadline = DEFAULT_FLUSH_DEADLINE
  5398  	}
  5399  	if opts.MaxClosedClients == 0 {
  5400  		opts.MaxClosedClients = DEFAULT_MAX_CLOSED_CLIENTS
  5401  	}
  5402  	if opts.LameDuckDuration == 0 {
  5403  		opts.LameDuckDuration = DEFAULT_LAME_DUCK_DURATION
  5404  	}
  5405  	if opts.LameDuckGracePeriod == 0 {
  5406  		opts.LameDuckGracePeriod = DEFAULT_LAME_DUCK_GRACE_PERIOD
  5407  	}
  5408  	if opts.Gateway.Port != 0 {
  5409  		if opts.Gateway.Host == _EMPTY_ {
  5410  			opts.Gateway.Host = DEFAULT_HOST
  5411  		}
  5412  		if opts.Gateway.TLSTimeout == 0 {
  5413  			opts.Gateway.TLSTimeout = float64(TLS_TIMEOUT) / float64(time.Second)
  5414  		}
  5415  		if opts.Gateway.AuthTimeout == 0 {
  5416  			opts.Gateway.AuthTimeout = getDefaultAuthTimeout(opts.Gateway.TLSConfig, opts.Gateway.TLSTimeout)
  5417  		}
  5418  	}
  5419  	if opts.ConnectErrorReports == 0 {
  5420  		opts.ConnectErrorReports = DEFAULT_CONNECT_ERROR_REPORTS
  5421  	}
  5422  	if opts.ReconnectErrorReports == 0 {
  5423  		opts.ReconnectErrorReports = DEFAULT_RECONNECT_ERROR_REPORTS
  5424  	}
  5425  	if opts.Websocket.Port != 0 {
  5426  		if opts.Websocket.Host == _EMPTY_ {
  5427  			opts.Websocket.Host = DEFAULT_HOST
  5428  		}
  5429  	}
  5430  	if opts.MQTT.Port != 0 {
  5431  		if opts.MQTT.Host == _EMPTY_ {
  5432  			opts.MQTT.Host = DEFAULT_HOST
  5433  		}
  5434  		if opts.MQTT.TLSTimeout == 0 {
  5435  			opts.MQTT.TLSTimeout = float64(TLS_TIMEOUT) / float64(time.Second)
  5436  		}
  5437  	}
  5438  	// JetStream
  5439  	if opts.JetStreamMaxMemory == 0 && !opts.maxMemSet {
  5440  		opts.JetStreamMaxMemory = -1
  5441  	}
  5442  	if opts.JetStreamMaxStore == 0 && !opts.maxStoreSet {
  5443  		opts.JetStreamMaxStore = -1
  5444  	}
  5445  	if opts.SyncInterval == 0 && !opts.syncSet {
  5446  		opts.SyncInterval = defaultSyncInterval
  5447  	}
  5448  }
  5449  
  5450  func getDefaultAuthTimeout(tls *tls.Config, tlsTimeout float64) float64 {
  5451  	var authTimeout float64
  5452  	if tls != nil {
  5453  		authTimeout = tlsTimeout + 1.0
  5454  	} else {
  5455  		authTimeout = float64(AUTH_TIMEOUT / time.Second)
  5456  	}
  5457  	return authTimeout
  5458  }
  5459  
  5460  // ConfigureOptions accepts a flag set and augments it with NATS Server
  5461  // specific flags. On success, an options structure is returned configured
  5462  // based on the selected flags and/or configuration file.
  5463  // The command line options take precedence to the ones in the configuration file.
  5464  func ConfigureOptions(fs *flag.FlagSet, args []string, printVersion, printHelp, printTLSHelp func()) (*Options, error) {
  5465  	opts := &Options{}
  5466  	var (
  5467  		showVersion            bool
  5468  		showHelp               bool
  5469  		showTLSHelp            bool
  5470  		signal                 string
  5471  		configFile             string
  5472  		dbgAndTrace            bool
  5473  		trcAndVerboseTrc       bool
  5474  		dbgAndTrcAndVerboseTrc bool
  5475  		err                    error
  5476  	)
  5477  
  5478  	fs.BoolVar(&showHelp, "h", false, "Show this message.")
  5479  	fs.BoolVar(&showHelp, "help", false, "Show this message.")
  5480  	fs.IntVar(&opts.Port, "port", 0, "Port to listen on.")
  5481  	fs.IntVar(&opts.Port, "p", 0, "Port to listen on.")
  5482  	fs.StringVar(&opts.ServerName, "n", _EMPTY_, "Server name.")
  5483  	fs.StringVar(&opts.ServerName, "name", _EMPTY_, "Server name.")
  5484  	fs.StringVar(&opts.ServerName, "server_name", _EMPTY_, "Server name.")
  5485  	fs.StringVar(&opts.Host, "addr", _EMPTY_, "Network host to listen on.")
  5486  	fs.StringVar(&opts.Host, "a", _EMPTY_, "Network host to listen on.")
  5487  	fs.StringVar(&opts.Host, "net", _EMPTY_, "Network host to listen on.")
  5488  	fs.StringVar(&opts.ClientAdvertise, "client_advertise", _EMPTY_, "Client URL to advertise to other servers.")
  5489  	fs.BoolVar(&opts.Debug, "D", false, "Enable Debug logging.")
  5490  	fs.BoolVar(&opts.Debug, "debug", false, "Enable Debug logging.")
  5491  	fs.BoolVar(&opts.Trace, "V", false, "Enable Trace logging.")
  5492  	fs.BoolVar(&trcAndVerboseTrc, "VV", false, "Enable Verbose Trace logging. (Traces system account as well)")
  5493  	fs.BoolVar(&opts.Trace, "trace", false, "Enable Trace logging.")
  5494  	fs.BoolVar(&dbgAndTrace, "DV", false, "Enable Debug and Trace logging.")
  5495  	fs.BoolVar(&dbgAndTrcAndVerboseTrc, "DVV", false, "Enable Debug and Verbose Trace logging. (Traces system account as well)")
  5496  	fs.BoolVar(&opts.Logtime, "T", true, "Timestamp log entries.")
  5497  	fs.BoolVar(&opts.Logtime, "logtime", true, "Timestamp log entries.")
  5498  	fs.BoolVar(&opts.LogtimeUTC, "logtime_utc", false, "Timestamps in UTC instead of local timezone.")
  5499  	fs.StringVar(&opts.Username, "user", _EMPTY_, "Username required for connection.")
  5500  	fs.StringVar(&opts.Password, "pass", _EMPTY_, "Password required for connection.")
  5501  	fs.StringVar(&opts.Authorization, "auth", _EMPTY_, "Authorization token required for connection.")
  5502  	fs.IntVar(&opts.HTTPPort, "m", 0, "HTTP Port for /varz, /connz endpoints.")
  5503  	fs.IntVar(&opts.HTTPPort, "http_port", 0, "HTTP Port for /varz, /connz endpoints.")
  5504  	fs.IntVar(&opts.HTTPSPort, "ms", 0, "HTTPS Port for /varz, /connz endpoints.")
  5505  	fs.IntVar(&opts.HTTPSPort, "https_port", 0, "HTTPS Port for /varz, /connz endpoints.")
  5506  	fs.StringVar(&configFile, "c", _EMPTY_, "Configuration file.")
  5507  	fs.StringVar(&configFile, "config", _EMPTY_, "Configuration file.")
  5508  	fs.BoolVar(&opts.CheckConfig, "t", false, "Check configuration and exit.")
  5509  	fs.StringVar(&signal, "sl", "", "Send signal to nats-server process (ldm, stop, quit, term, reopen, reload).")
  5510  	fs.StringVar(&signal, "signal", "", "Send signal to nats-server process (ldm, stop, quit, term, reopen, reload).")
  5511  	fs.StringVar(&opts.PidFile, "P", "", "File to store process pid.")
  5512  	fs.StringVar(&opts.PidFile, "pid", "", "File to store process pid.")
  5513  	fs.StringVar(&opts.PortsFileDir, "ports_file_dir", "", "Creates a ports file in the specified directory (<executable_name>_<pid>.ports).")
  5514  	fs.StringVar(&opts.LogFile, "l", "", "File to store logging output.")
  5515  	fs.StringVar(&opts.LogFile, "log", "", "File to store logging output.")
  5516  	fs.Int64Var(&opts.LogSizeLimit, "log_size_limit", 0, "Logfile size limit being auto-rotated")
  5517  	fs.BoolVar(&opts.Syslog, "s", false, "Enable syslog as log method.")
  5518  	fs.BoolVar(&opts.Syslog, "syslog", false, "Enable syslog as log method.")
  5519  	fs.StringVar(&opts.RemoteSyslog, "r", _EMPTY_, "Syslog server addr (udp://127.0.0.1:514).")
  5520  	fs.StringVar(&opts.RemoteSyslog, "remote_syslog", _EMPTY_, "Syslog server addr (udp://127.0.0.1:514).")
  5521  	fs.BoolVar(&showVersion, "version", false, "Print version information.")
  5522  	fs.BoolVar(&showVersion, "v", false, "Print version information.")
  5523  	fs.IntVar(&opts.ProfPort, "profile", 0, "Profiling HTTP port.")
  5524  	fs.StringVar(&opts.RoutesStr, "routes", _EMPTY_, "Routes to actively solicit a connection.")
  5525  	fs.StringVar(&opts.Cluster.ListenStr, "cluster", _EMPTY_, "Cluster url from which members can solicit routes.")
  5526  	fs.StringVar(&opts.Cluster.ListenStr, "cluster_listen", _EMPTY_, "Cluster url from which members can solicit routes.")
  5527  	fs.StringVar(&opts.Cluster.Advertise, "cluster_advertise", _EMPTY_, "Cluster URL to advertise to other servers.")
  5528  	fs.BoolVar(&opts.Cluster.NoAdvertise, "no_advertise", false, "Advertise known cluster IPs to clients.")
  5529  	fs.IntVar(&opts.Cluster.ConnectRetries, "connect_retries", 0, "For implicit routes, number of connect retries.")
  5530  	fs.StringVar(&opts.Cluster.Name, "cluster_name", _EMPTY_, "Cluster Name, if not set one will be dynamically generated.")
  5531  	fs.BoolVar(&showTLSHelp, "help_tls", false, "TLS help.")
  5532  	fs.BoolVar(&opts.TLS, "tls", false, "Enable TLS.")
  5533  	fs.BoolVar(&opts.TLSVerify, "tlsverify", false, "Enable TLS with client verification.")
  5534  	fs.StringVar(&opts.TLSCert, "tlscert", _EMPTY_, "Server certificate file.")
  5535  	fs.StringVar(&opts.TLSKey, "tlskey", _EMPTY_, "Private key for server certificate.")
  5536  	fs.StringVar(&opts.TLSCaCert, "tlscacert", _EMPTY_, "Client certificate CA for verification.")
  5537  	fs.IntVar(&opts.MaxTracedMsgLen, "max_traced_msg_len", 0, "Maximum printable length for traced messages. 0 for unlimited.")
  5538  	fs.BoolVar(&opts.JetStream, "js", false, "Enable JetStream.")
  5539  	fs.BoolVar(&opts.JetStream, "jetstream", false, "Enable JetStream.")
  5540  	fs.StringVar(&opts.StoreDir, "sd", _EMPTY_, "Storage directory.")
  5541  	fs.StringVar(&opts.StoreDir, "store_dir", _EMPTY_, "Storage directory.")
  5542  
  5543  	// The flags definition above set "default" values to some of the options.
  5544  	// Calling Parse() here will override the default options with any value
  5545  	// specified from the command line. This is ok. We will then update the
  5546  	// options with the content of the configuration file (if present), and then,
  5547  	// call Parse() again to override the default+config with command line values.
  5548  	// Calling Parse() before processing config file is necessary since configFile
  5549  	// itself is a command line argument, and also Parse() is required in order
  5550  	// to know if user wants simply to show "help" or "version", etc...
  5551  	if err := fs.Parse(args); err != nil {
  5552  		return nil, err
  5553  	}
  5554  
  5555  	if showVersion {
  5556  		printVersion()
  5557  		return nil, nil
  5558  	}
  5559  
  5560  	if showHelp {
  5561  		printHelp()
  5562  		return nil, nil
  5563  	}
  5564  
  5565  	if showTLSHelp {
  5566  		printTLSHelp()
  5567  		return nil, nil
  5568  	}
  5569  
  5570  	// Process args looking for non-flag options,
  5571  	// 'version' and 'help' only for now
  5572  	showVersion, showHelp, err = ProcessCommandLineArgs(fs)
  5573  	if err != nil {
  5574  		return nil, err
  5575  	} else if showVersion {
  5576  		printVersion()
  5577  		return nil, nil
  5578  	} else if showHelp {
  5579  		printHelp()
  5580  		return nil, nil
  5581  	}
  5582  
  5583  	// Snapshot flag options.
  5584  	FlagSnapshot = opts.Clone()
  5585  
  5586  	// Keep track of the boolean flags that were explicitly set with their value.
  5587  	fs.Visit(func(f *flag.Flag) {
  5588  		switch f.Name {
  5589  		case "DVV":
  5590  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Debug", dbgAndTrcAndVerboseTrc)
  5591  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Trace", dbgAndTrcAndVerboseTrc)
  5592  			trackExplicitVal(&FlagSnapshot.inCmdLine, "TraceVerbose", dbgAndTrcAndVerboseTrc)
  5593  		case "DV":
  5594  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Debug", dbgAndTrace)
  5595  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Trace", dbgAndTrace)
  5596  		case "D":
  5597  			fallthrough
  5598  		case "debug":
  5599  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Debug", FlagSnapshot.Debug)
  5600  		case "VV":
  5601  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Trace", trcAndVerboseTrc)
  5602  			trackExplicitVal(&FlagSnapshot.inCmdLine, "TraceVerbose", trcAndVerboseTrc)
  5603  		case "V":
  5604  			fallthrough
  5605  		case "trace":
  5606  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Trace", FlagSnapshot.Trace)
  5607  		case "T":
  5608  			fallthrough
  5609  		case "logtime":
  5610  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Logtime", FlagSnapshot.Logtime)
  5611  		case "s":
  5612  			fallthrough
  5613  		case "syslog":
  5614  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Syslog", FlagSnapshot.Syslog)
  5615  		case "no_advertise":
  5616  			trackExplicitVal(&FlagSnapshot.inCmdLine, "Cluster.NoAdvertise", FlagSnapshot.Cluster.NoAdvertise)
  5617  		}
  5618  	})
  5619  
  5620  	// Process signal control.
  5621  	if signal != _EMPTY_ {
  5622  		if err := processSignal(signal); err != nil {
  5623  			return nil, err
  5624  		}
  5625  	}
  5626  
  5627  	// Parse config if given
  5628  	if configFile != _EMPTY_ {
  5629  		// This will update the options with values from the config file.
  5630  		err := opts.ProcessConfigFile(configFile)
  5631  		if err != nil {
  5632  			if opts.CheckConfig {
  5633  				return nil, err
  5634  			}
  5635  			if cerr, ok := err.(*processConfigErr); !ok || len(cerr.Errors()) != 0 {
  5636  				return nil, err
  5637  			}
  5638  			// If we get here we only have warnings and can still continue
  5639  			fmt.Fprint(os.Stderr, err)
  5640  		} else if opts.CheckConfig {
  5641  			// Report configuration file syntax test was successful and exit.
  5642  			return opts, nil
  5643  		}
  5644  
  5645  		// Call this again to override config file options with options from command line.
  5646  		// Note: We don't need to check error here since if there was an error, it would
  5647  		// have been caught the first time this function was called (after setting up the
  5648  		// flags).
  5649  		fs.Parse(args)
  5650  	} else if opts.CheckConfig {
  5651  		return nil, fmt.Errorf("must specify [-c, --config] option to check configuration file syntax")
  5652  	}
  5653  
  5654  	// Special handling of some flags
  5655  	var (
  5656  		flagErr     error
  5657  		tlsDisabled bool
  5658  		tlsOverride bool
  5659  	)
  5660  	fs.Visit(func(f *flag.Flag) {
  5661  		// short-circuit if an error was encountered
  5662  		if flagErr != nil {
  5663  			return
  5664  		}
  5665  		if strings.HasPrefix(f.Name, "tls") {
  5666  			if f.Name == "tls" {
  5667  				if !opts.TLS {
  5668  					// User has specified "-tls=false", we need to disable TLS
  5669  					opts.TLSConfig = nil
  5670  					tlsDisabled = true
  5671  					tlsOverride = false
  5672  					return
  5673  				}
  5674  				tlsOverride = true
  5675  			} else if !tlsDisabled {
  5676  				tlsOverride = true
  5677  			}
  5678  		} else {
  5679  			switch f.Name {
  5680  			case "VV":
  5681  				opts.Trace, opts.TraceVerbose = trcAndVerboseTrc, trcAndVerboseTrc
  5682  			case "DVV":
  5683  				opts.Trace, opts.Debug, opts.TraceVerbose = dbgAndTrcAndVerboseTrc, dbgAndTrcAndVerboseTrc, dbgAndTrcAndVerboseTrc
  5684  			case "DV":
  5685  				// Check value to support -DV=false
  5686  				opts.Trace, opts.Debug = dbgAndTrace, dbgAndTrace
  5687  			case "cluster", "cluster_listen":
  5688  				// Override cluster config if explicitly set via flags.
  5689  				flagErr = overrideCluster(opts)
  5690  			case "routes":
  5691  				// Keep in mind that the flag has updated opts.RoutesStr at this point.
  5692  				if opts.RoutesStr == _EMPTY_ {
  5693  					// Set routes array to nil since routes string is empty
  5694  					opts.Routes = nil
  5695  					return
  5696  				}
  5697  				routeUrls := RoutesFromStr(opts.RoutesStr)
  5698  				opts.Routes = routeUrls
  5699  			}
  5700  		}
  5701  	})
  5702  	if flagErr != nil {
  5703  		return nil, flagErr
  5704  	}
  5705  
  5706  	// This will be true if some of the `-tls` params have been set and
  5707  	// `-tls=false` has not been set.
  5708  	if tlsOverride {
  5709  		if err := overrideTLS(opts); err != nil {
  5710  			return nil, err
  5711  		}
  5712  	}
  5713  
  5714  	// If we don't have cluster defined in the configuration
  5715  	// file and no cluster listen string override, but we do
  5716  	// have a routes override, we need to report misconfiguration.
  5717  	if opts.RoutesStr != _EMPTY_ && opts.Cluster.ListenStr == _EMPTY_ && opts.Cluster.Host == _EMPTY_ && opts.Cluster.Port == 0 {
  5718  		return nil, errors.New("solicited routes require cluster capabilities, e.g. --cluster")
  5719  	}
  5720  
  5721  	return opts, nil
  5722  }
  5723  
  5724  func normalizeBasePath(p string) string {
  5725  	if len(p) == 0 {
  5726  		return "/"
  5727  	}
  5728  	// add leading slash
  5729  	if p[0] != '/' {
  5730  		p = "/" + p
  5731  	}
  5732  	return path.Clean(p)
  5733  }
  5734  
  5735  // overrideTLS is called when at least "-tls=true" has been set.
  5736  func overrideTLS(opts *Options) error {
  5737  	if opts.TLSCert == _EMPTY_ {
  5738  		return errors.New("TLS Server certificate must be present and valid")
  5739  	}
  5740  	if opts.TLSKey == _EMPTY_ {
  5741  		return errors.New("TLS Server private key must be present and valid")
  5742  	}
  5743  
  5744  	tc := TLSConfigOpts{}
  5745  	tc.CertFile = opts.TLSCert
  5746  	tc.KeyFile = opts.TLSKey
  5747  	tc.CaFile = opts.TLSCaCert
  5748  	tc.Verify = opts.TLSVerify
  5749  	tc.Ciphers = defaultCipherSuites()
  5750  
  5751  	var err error
  5752  	opts.TLSConfig, err = GenTLSConfig(&tc)
  5753  	return err
  5754  }
  5755  
  5756  // overrideCluster updates Options.Cluster if that flag "cluster" (or "cluster_listen")
  5757  // has explicitly be set in the command line. If it is set to empty string, it will
  5758  // clear the Cluster options.
  5759  func overrideCluster(opts *Options) error {
  5760  	if opts.Cluster.ListenStr == _EMPTY_ {
  5761  		// This one is enough to disable clustering.
  5762  		opts.Cluster.Port = 0
  5763  		return nil
  5764  	}
  5765  	// -1 will fail url.Parse, so if we have -1, change it to
  5766  	// 0, and then after parse, replace the port with -1 so we get
  5767  	// automatic port allocation
  5768  	wantsRandom := false
  5769  	if strings.HasSuffix(opts.Cluster.ListenStr, ":-1") {
  5770  		wantsRandom = true
  5771  		cls := fmt.Sprintf("%s:0", opts.Cluster.ListenStr[0:len(opts.Cluster.ListenStr)-3])
  5772  		opts.Cluster.ListenStr = cls
  5773  	}
  5774  	clusterURL, err := url.Parse(opts.Cluster.ListenStr)
  5775  	if err != nil {
  5776  		return err
  5777  	}
  5778  	h, p, err := net.SplitHostPort(clusterURL.Host)
  5779  	if err != nil {
  5780  		return err
  5781  	}
  5782  	if wantsRandom {
  5783  		p = "-1"
  5784  	}
  5785  	opts.Cluster.Host = h
  5786  	_, err = fmt.Sscan(p, &opts.Cluster.Port)
  5787  	if err != nil {
  5788  		return err
  5789  	}
  5790  
  5791  	if clusterURL.User != nil {
  5792  		pass, hasPassword := clusterURL.User.Password()
  5793  		if !hasPassword {
  5794  			return errors.New("expected cluster password to be set")
  5795  		}
  5796  		opts.Cluster.Password = pass
  5797  
  5798  		user := clusterURL.User.Username()
  5799  		opts.Cluster.Username = user
  5800  	} else {
  5801  		// Since we override from flag and there is no user/pwd, make
  5802  		// sure we clear what we may have gotten from config file.
  5803  		opts.Cluster.Username = _EMPTY_
  5804  		opts.Cluster.Password = _EMPTY_
  5805  	}
  5806  
  5807  	return nil
  5808  }
  5809  
  5810  func processSignal(signal string) error {
  5811  	var (
  5812  		pid           string
  5813  		commandAndPid = strings.Split(signal, "=")
  5814  	)
  5815  	if l := len(commandAndPid); l == 2 {
  5816  		pid = maybeReadPidFile(commandAndPid[1])
  5817  	} else if l > 2 {
  5818  		return fmt.Errorf("invalid signal parameters: %v", commandAndPid[2:])
  5819  	}
  5820  	if err := ProcessSignal(Command(commandAndPid[0]), pid); err != nil {
  5821  		return err
  5822  	}
  5823  	os.Exit(0)
  5824  	return nil
  5825  }
  5826  
  5827  // maybeReadPidFile returns a PID or Windows service name obtained via the following method:
  5828  // 1. Try to open a file with path "pidStr" (absolute or relative).
  5829  // 2. If such a file exists and can be read, return its contents.
  5830  // 3. Otherwise, return the original "pidStr" string.
  5831  func maybeReadPidFile(pidStr string) string {
  5832  	if b, err := os.ReadFile(pidStr); err == nil {
  5833  		return string(b)
  5834  	}
  5835  	return pidStr
  5836  }
  5837  
  5838  func homeDir() (string, error) {
  5839  	if runtime.GOOS == "windows" {
  5840  		homeDrive, homePath := os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH")
  5841  		userProfile := os.Getenv("USERPROFILE")
  5842  
  5843  		home := filepath.Join(homeDrive, homePath)
  5844  		if homeDrive == _EMPTY_ || homePath == _EMPTY_ {
  5845  			if userProfile == _EMPTY_ {
  5846  				return _EMPTY_, errors.New("nats: failed to get home dir, require %HOMEDRIVE% and %HOMEPATH% or %USERPROFILE%")
  5847  			}
  5848  			home = userProfile
  5849  		}
  5850  
  5851  		return home, nil
  5852  	}
  5853  
  5854  	home := os.Getenv("HOME")
  5855  	if home == _EMPTY_ {
  5856  		return _EMPTY_, errors.New("failed to get home dir, require $HOME")
  5857  	}
  5858  	return home, nil
  5859  }
  5860  
  5861  func expandPath(p string) (string, error) {
  5862  	p = os.ExpandEnv(p)
  5863  
  5864  	if !strings.HasPrefix(p, "~") {
  5865  		return p, nil
  5866  	}
  5867  
  5868  	home, err := homeDir()
  5869  	if err != nil {
  5870  		return _EMPTY_, err
  5871  	}
  5872  
  5873  	return filepath.Join(home, p[1:]), nil
  5874  }