65 lines
2.3 KiB
Go
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
|
|
},
|
|
}
|
|
}
|