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