Files
mesh-sdk/go/process/conn.go
T

65 lines
2.3 KiB
Go

package process
import (
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"errors"
"fmt"
"github.com/nats-io/nats.go"
)
// Conn is one process's own connection to the bus (novox/hq ADR 0436 clause 4): dialled with the account
// the controller delivered, pinned to its fingerprint, on its own inbox prefix. It offers no Serve and no
// way to serve a tool — a process reaches the bus only as itself, and never answers a call.
type Conn struct {
nc *nats.Conn
account Account
}
// Connect dials the bus with account: pinned to its fingerprint when it carries one (refused with any
// other certificate), authenticated as its user and password, on the inbox prefix _INBOX.<user> and no
// other. Ported from mesh-controller internal/broker/jetstream.go:106-132 (DialPinned,
// PinnedToFingerprint) since this package may not import the controller.
func Connect(account Account, opts ...nats.Option) (*Conn, error) {
all := []nats.Option{
nats.CustomInboxPrefix(account.InboxPrefix()),
nats.UserInfo(account.User, account.Password),
}
if account.Fingerprint != "" {
all = append(all, nats.Secure(pinnedToFingerprint(account.Fingerprint)))
}
all = append(all, opts...)
nc, err := nats.Connect(account.URL, all...)
if err != nil {
return nil, fmt.Errorf("connecting the process account %s: %w", account.User, err)
}
return &Conn{nc: nc, account: account}, nil
}
// Close ends the connection.
func (c *Conn) Close() { c.nc.Close() }
// pinnedToFingerprint accepts exactly the certificate with this SHA-256 and no other — the leaf alone, its
// name and chain deliberately not consulted, as mesh-controller's own pin does (jetstream.go:116-132).
func pinnedToFingerprint(want string) *tls.Config {
return &tls.Config{
InsecureSkipVerify: true, //nolint:gosec // replaced by the pin below, which is stricter
MinVersion: tls.VersionTLS12,
VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
if len(rawCerts) == 0 {
return errors.New("the bus presented no certificate")
}
sum := sha256.Sum256(rawCerts[0])
got := "sha256:" + hex.EncodeToString(sum[:])
if got != want {
return fmt.Errorf("the bus presented a certificate this mesh does not know (%s…), expected %s…",
got[:23], want[:23])
}
return nil
},
}
}