The seat mesh-enrolment's tokens answers the token sealed to the operator key; the operator opens it at their own terminal. The subcommand reads the sealed token on standard input and the private key from a file, prints the token text a joining machine takes, asks nothing of the node-engine's socket, and says the token is not sealed to a wrong key (ADR 0587 §6, §8). New: one table-style test function; mesh-cli had 6, so none was merged or deleted. (issue 774, 774/S51) Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
81 lines
3.5 KiB
Go
81 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/crypto/nacl/box"
|
|
)
|
|
|
|
// 774/S51/AC1, AC2 (novox/hq ADR 0587 §6, §8): a token sealed to a test operator key (as mesh-vault seals it: the text
|
|
// of the token, anonymous box, base64) is opened with the private half and printed as a token the engine's parser reads
|
|
// (base64url of version 1 JSON with node, broker, fingerprint, signer and secret), and nothing is asked of the engine's
|
|
// socket, which here is a path nobody listens on; the wrong key prints nothing and says the token is not sealed to it.
|
|
func TestEnrolOpenOpensASealedTokenLocallyAndOnlyWithItsKey(t *testing.T) {
|
|
t.Setenv("MESH_VERB", "")
|
|
token := base64.RawURLEncoding.EncodeToString([]byte(`{"v":1,"node":"new1","broker":"tls://10.77.0.1:4222",` +
|
|
`"fingerprint":"sha256:bus","signer":"` + base64.StdEncoding.EncodeToString(make([]byte, 32)) + `","secret":"one-time"}`))
|
|
pub, priv, _ := box.GenerateKey(rand.Reader)
|
|
_, otherPriv, _ := box.GenerateKey(rand.Reader)
|
|
sealed, err := box.SealAnonymous(nil, []byte(token), pub, rand.Reader)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dir := t.TempDir()
|
|
keyFile := func(name string, k *[32]byte) string {
|
|
p := filepath.Join(dir, name)
|
|
if err := os.WriteFile(p, []byte(base64.StdEncoding.EncodeToString(k[:])+"\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return p
|
|
}
|
|
before, beforeIn := socket, standardInput
|
|
socket = filepath.Join(dir, "nobody-listens.sock")
|
|
t.Cleanup(func() { socket, standardInput = before, beforeIn })
|
|
for _, c := range []struct {
|
|
name string
|
|
args []string
|
|
stdin string
|
|
code int
|
|
out string
|
|
err string
|
|
}{
|
|
{"the right key", []string{"enrol", "open", "--key", keyFile("op", priv)}, base64.StdEncoding.EncodeToString(sealed) + "\n", 0, token + "\n", ""},
|
|
{"the key as --key=", []string{"enrol", "open", "--key=" + keyFile("op2", priv)}, base64.StdEncoding.EncodeToString(sealed), 0, token + "\n", ""},
|
|
{"the wrong key", []string{"enrol", "open", "--key", keyFile("other", otherPriv)}, base64.StdEncoding.EncodeToString(sealed), 1, "", "not sealed to that key"},
|
|
{"no key", []string{"enrol", "open"}, base64.StdEncoding.EncodeToString(sealed), 2, "", "nox enrol open --key"},
|
|
{"not a sealed token", []string{"enrol", "open", "--key", keyFile("op3", priv)}, "@@@", 1, "", "not a sealed token"},
|
|
} {
|
|
standardInput = func() (io.Reader, bool) { return strings.NewReader(c.stdin), false }
|
|
var out, errOut bytes.Buffer
|
|
code := run(context.Background(), c.args, &out, &errOut)
|
|
if code != c.code || out.String() != c.out || !strings.Contains(errOut.String(), c.err) {
|
|
t.Errorf("%s: exit %d, stdout %q, stderr %q", c.name, code, out.String(), errOut.String())
|
|
}
|
|
}
|
|
// What it prints is a token the engine's parser reads.
|
|
var parsed struct {
|
|
V int `json:"v"`
|
|
Node string `json:"node"`
|
|
Secret string `json:"secret"`
|
|
}
|
|
raw, _ := base64.RawURLEncoding.DecodeString(token)
|
|
if json.Unmarshal(raw, &parsed) != nil || parsed.V != 1 || parsed.Node != "new1" || parsed.Secret != "one-time" {
|
|
t.Errorf("the token is %+v", parsed)
|
|
}
|
|
// Standard input a terminal is never read.
|
|
standardInput = func() (io.Reader, bool) { return strings.NewReader("x"), true }
|
|
var out, errOut bytes.Buffer
|
|
if code := run(context.Background(), []string{"enrol", "open", "--key", keyFile("op4", priv)}, &out, &errOut); code != 2 || out.Len() != 0 {
|
|
t.Errorf("a terminal on standard input: exit %d, stdout %q", code, out.String())
|
|
}
|
|
}
|