116 lines
3.9 KiB
Go
116 lines
3.9 KiB
Go
//go:build integration
|
|
|
|
package process
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"math/big"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nats-io/nats-server/v2/server"
|
|
)
|
|
|
|
// selfSignedServer is a nats-server with JetStream and TLS, self-signed, for this test alone (mirroring
|
|
// go/internal/testbus.Start, with a certificate added since testbus has none): a mesh's bus presents its own
|
|
// certificate in no public trust store, which is exactly what a process pins to (ADR 0436 clause 4).
|
|
func selfSignedServer(t *testing.T) (url, fingerprint string) {
|
|
t.Helper()
|
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tmpl := &x509.Certificate{
|
|
SerialNumber: big.NewInt(1),
|
|
Subject: pkix.Name{CommonName: "mesh-sdk-test-bus"},
|
|
NotBefore: time.Now().Add(-time.Hour),
|
|
NotAfter: time.Now().Add(time.Hour),
|
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
}
|
|
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sum := sha256.Sum256(der)
|
|
fingerprint = "sha256:" + hex.EncodeToString(sum[:])
|
|
cert := tls.Certificate{Certificate: [][]byte{der}, PrivateKey: key}
|
|
opts := &server.Options{Host: "127.0.0.1", Port: server.RANDOM_PORT, JetStream: true, StoreDir: t.TempDir(),
|
|
NoLog: true, NoSigs: true, TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}},
|
|
Username: "novox.mesh-mail.send", Password: "the-pw"}
|
|
s, err := server.NewServer(opts)
|
|
if err != nil {
|
|
t.Fatalf("a TLS bus for this test could not be made: %v", err)
|
|
}
|
|
go s.Start()
|
|
if !s.ReadyForConnections(10 * time.Second) {
|
|
s.Shutdown()
|
|
t.Fatal("a TLS bus for this test did not come up within 10s")
|
|
}
|
|
t.Cleanup(func() {
|
|
s.Shutdown()
|
|
s.WaitForShutdown()
|
|
})
|
|
return s.ClientURL(), fingerprint
|
|
}
|
|
|
|
// mailSenderAccount is the account novox.mesh-mail.send would be delivered as, the module's own secret
|
|
// broker-send: written to a file and read back through ReadAccount (1171/AC2), exactly as a process
|
|
// reads it, rather than built by hand.
|
|
func mailSenderAccount(t *testing.T, url, fingerprint string) Account {
|
|
t.Helper()
|
|
data, err := json.Marshal(map[string]any{
|
|
"url": url, "fingerprint": fingerprint, "node": "novox", "module": "mesh-mail",
|
|
"user": "novox.mesh-mail.send", "password": "the-pw",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
path := filepath.Join(t.TempDir(), "broker-send")
|
|
if err := os.WriteFile(path, data, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
account, err := ReadAccount(path)
|
|
if err != nil {
|
|
t.Fatalf("ReadAccount on a well-formed file: %v", err)
|
|
}
|
|
return account
|
|
}
|
|
|
|
// 1171/AC3: given a test bus with TLS and the account composed for novox.mesh-mail.send, when the package
|
|
// connects with the file, then it connects with the inbox prefix _INBOX.novox.mesh-mail.send.
|
|
func TestConnectPinsTheFingerprintAndSetsTheInboxPrefix(t *testing.T) {
|
|
url, fingerprint := selfSignedServer(t)
|
|
account := mailSenderAccount(t, url, fingerprint)
|
|
conn, err := Connect(account)
|
|
if err != nil {
|
|
t.Fatalf("connecting with the right fingerprint was refused: %v", err)
|
|
}
|
|
defer conn.Close()
|
|
if !conn.nc.IsConnected() {
|
|
t.Fatal("the connection did not come up")
|
|
}
|
|
if got := conn.nc.Opts.InboxPrefix; got != "_INBOX.novox.mesh-mail.send" {
|
|
t.Errorf("inbox prefix: %q, want %q", got, "_INBOX.novox.mesh-mail.send")
|
|
}
|
|
}
|
|
|
|
// 1171/AC3: connecting with a fingerprint that is not the bus's own leaf certificate is refused.
|
|
func TestConnectRefusesTheWrongFingerprint(t *testing.T) {
|
|
url, _ := selfSignedServer(t)
|
|
account := mailSenderAccount(t, url, "sha256:0000000000000000000000000000000000000000000000000000000000000000")
|
|
if _, err := Connect(account); err == nil {
|
|
t.Fatal("connecting with the wrong fingerprint was not refused")
|
|
}
|
|
}
|