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(<, &retErr) 827 configure := func(v any) error { 828 tk, v := unwrapValue(v, <) 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(<, errors) 899 900 tk, v := unwrapValue(v, <) 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, <) 1298 dir = v.(string) 1299 } 1300 if v, ok := v["type"]; ok { 1301 _, v := unwrapValue(v, <) 1302 dirType = v.(string) 1303 } 1304 if v, ok := v["allow_delete"]; ok { 1305 _, v := unwrapValue(v, <) 1306 del = v.(bool) 1307 } 1308 if v, ok := v["hard_delete"]; ok { 1309 _, v := unwrapValue(v, <) 1310 hdel_set = true 1311 hdel = v.(bool) 1312 } 1313 if v, ok := v["limit"]; ok { 1314 _, v := unwrapValue(v, <) 1315 limit = v.(int64) 1316 } 1317 if v, ok := v["ttl"]; ok { 1318 _, v := unwrapValue(v, <) 1319 ttl, err = time.ParseDuration(v.(string)) 1320 } 1321 if v, ok := v["interval"]; err == nil && ok { 1322 _, v := unwrapValue(v, <) 1323 sync, err = time.ParseDuration(v.(string)) 1324 } 1325 if v, ok := v["timeout"]; err == nil && ok { 1326 _, v := unwrapValue(v, <) 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, <) 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, <) 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, <) 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(<, errors) 1676 1677 tk, v := unwrapValue(v, <) 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, <) 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, <, 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(<, &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, <) 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, <) 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(<, &errors) 1864 1865 dd := make(map[string]bool) 1866 1867 for _, u := range a { 1868 tk, u := unwrapValue(u, <) 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(<, errors) 1907 1908 tk, v := unwrapValue(v, <) 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, <) 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, <) 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, <) 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, <) 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, <) 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, <) 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, <) 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, <) 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, <) 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(<, errors) 2333 2334 tk, v := unwrapValue(v, <) 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, <) 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(<, errors) 2444 2445 _, v = unwrapValue(v, <) 2446 am = v.(map[string]any) 2447 for mk, mv := range am { 2448 tk, mv = unwrapValue(mv, <) 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(<, errors) 2504 2505 tk, mv = unwrapValue(mv, <) 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, <) 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, <) 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(<, errors) 2557 tk, v := unwrapValue(v, <) 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, <) 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, <) 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(<, errors) 2712 2713 tk, v := unwrapValue(v, <) 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, <) 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, <) 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, <) 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(<, errors) 2896 2897 tk, v := unwrapValue(v, <) 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, <) 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, <) 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, <) 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(<, errors) 2957 2958 tk, v := unwrapValue(mv, <) 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, <) 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, <) 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, <) 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(<, errors) 3059 3060 tk, v := unwrapValue(v, <) 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, <) 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, <) 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, <) 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(<, errors) 3378 3379 // This should be an array of objects/maps. 3380 tk, v := unwrapValue(v, <) 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(<, errors) 3412 3413 // This should be an array of objects/maps. 3414 tk, v := unwrapValue(v, <) 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, <) 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(<, errors) 3456 3457 var accountName, subject string 3458 for mk, mv := range v { 3459 tk, mv := unwrapValue(mv, <) 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(<, errors) 3505 3506 tk, v := unwrapValue(v, <) 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, <) 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, <) 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(<, &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, <) 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, <) 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(<, errors) 3788 3789 tk, mv := unwrapValue(v, <) 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, <) 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(<, errors) 3942 3943 _, v = unwrapValue(v, <) 3944 am = v.(map[string]any) 3945 for mk, mv := range am { 3946 tk, mv = unwrapValue(mv, <) 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(<, errors) 4012 tk, mv = unwrapValue(mv, <) 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, <) 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, <) 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, <, 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(<, errors) 4121 4122 tk, mv = unwrapValue(mv, <) 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, <) 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, <) 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(<, errors) 4181 4182 tk, mv = unwrapValue(mv, <) 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, <) 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(<, errors) 4257 4258 tk, v := unwrapValue(v, <) 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, <) 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(<, errors) 4289 4290 tk, v := unwrapValue(v, <) 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, <) 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(<, 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, <) 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(<, &retErr) 4448 4449 tk, v := unwrapValue(v, <) 4450 tlsm = v.(map[string]any) 4451 for mk, mv := range tlsm { 4452 tk, mv := unwrapValue(mv, <) 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, <) 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, <) 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, <) 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, <) 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, <) 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(<, errors) 4734 4735 _, v = unwrapValue(v, <) 4736 am = v.(map[string]any) 4737 for mk, mv := range am { 4738 tk, mv = unwrapValue(mv, <) 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(<, errors) 4798 4799 tk, v := unwrapValue(v, <) 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, <) 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, <, 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, <) 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(<, errors) 4915 4916 tk, v := unwrapValue(v, <) 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, <) 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 }