1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package test

import (
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"rss-kakapo/dal"
	"rss-kakapo/logic"
	"rss-kakapo/shared"
	"rss-kakapo/texts"
	"testing"
)

// mustParsePub parses a PKCS#1 public key in a PEM block, as the accounts
// store and the actor documents show it.
func mustParsePub(t *testing.T, pubPem string) *rsa.PublicKey {
	t.Helper()
	block, _ := pem.Decode([]byte(pubPem))
	if block == nil {
		t.Fatalf("not a PEM block: %q", pubPem)
	}
	key, err := x509.ParsePKCS1PublicKey(block.Bytes)
	if err != nil {
		t.Fatal(err)
	}
	return key
}

// birbCfg is the configuration of an instance whose birb is called user. It
// names no keys: there is nowhere to put them any more.
func birbCfg(user string) *shared.Config {
	return &shared.Config{
		Host: "kakapo.example.org",
		Birb: &shared.UserInfo{User: user},
	}
}

func ensureBirb(t *testing.T, cfg *shared.Config, repo dal.IRepo) error {
	t.Helper()
	return logic.EnsureBirb(cfg, repo, logic.NewKeyStore(cfg, repo),
		shared.RealClock{}, newTestLogger())
}

// The birb's account is created with a key pair of its own, so an instance
// starts on an empty database with nothing configured and nothing generated
// by hand beforehand.
func TestEnsureBirbCreatesTheAccountWithAKey(t *testing.T) {
	cfg := birbCfg("birb")
	repo := newTestRepo(t, cfg) // calls EnsureBirb

	stored, err := repo.GetPrivKey("birb")
	if err != nil {
		t.Fatal(err)
	}
	key, err := logic.ParsePrivKey(stored)
	if err != nil {
		t.Fatalf("the birb's stored key: %v", err)
	}

	// The actor document shows the public half of exactly that key: a
	// signature it makes is checked against what this serves.
	udir := logic.NewUserDirectory(cfg, newTestLogger(), repo,
		logic.NewKeyStore(cfg, repo), nil, texts.NewTexts())
	ui := udir.GetUserInfo("birb")
	if ui == nil {
		t.Fatal("GetUserInfo(birb) = nil")
	}
	if !key.PublicKey.Equal(mustParsePub(t, ui.PublicKey.PublicKeyPem)) {
		t.Error("the actor document shows a key other than the one it signs with")
	}
	if ui.Published == "" {
		t.Error("the actor document has no published date")
	}
}

// Started again, the account is left as it is: a new key pair would be one no
// other server knows the birb by.
func TestEnsureBirbKeepsTheKeyOnTheNextStart(t *testing.T) {
	cfg := birbCfg("birb")
	repo := newTestRepo(t, cfg)
	first, err := repo.GetPrivKey("birb")
	if err != nil {
		t.Fatal(err)
	}

	for i := 0; i < 2; i++ {
		if err := ensureBirb(t, cfg, repo); err != nil {
			t.Fatalf("EnsureBirb: %v", err)
		}
	}

	again, err := repo.GetPrivKey("birb")
	if err != nil {
		t.Fatal(err)
	}
	if again != first {
		t.Error("the birb's key changed on a later start")
	}
}

// A renamed birb gets an account of its own. Upstream created the account
// only when the database was created, so a rename left the instance with a
// birb that had no row, no key and no actor document.
func TestEnsureBirbCreatesAnAccountForARenamedBirb(t *testing.T) {
	cfg := birbCfg("birb")
	repo := newTestRepo(t, cfg)

	cfg.Birb.User = "parrot"
	if err := ensureBirb(t, cfg, repo); err != nil {
		t.Fatalf("EnsureBirb after rename: %v", err)
	}

	stored, err := repo.GetPrivKey("parrot")
	if err != nil {
		t.Fatal(err)
	}
	if _, err := logic.ParsePrivKey(stored); err != nil {
		t.Errorf("the renamed birb has no usable key: %v", err)
	}
}

// An account that has lost its private key is refused, rather than given a
// new one: that is a database restored without its keys, where minting a new
// identity under the old name is the wrong answer.
func TestEnsureBirbRefusesAnAccountWithoutAKey(t *testing.T) {
	cfg := birbCfg("birb")
	repo := newTestRepo(t, cfg)
	if err := repo.SetPrivKey("birb", ""); err != nil {
		t.Fatal(err)
	}

	if err := ensureBirb(t, cfg, repo); err == nil {
		t.Error("EnsureBirb accepted an account with no private key")
	}
}

func TestEnsureBirbRefusesAnEmptyBirbUser(t *testing.T) {
	cfg := birbCfg("birb")
	repo := newTestRepo(t, cfg)

	cfg.Birb.User = ""
	if err := ensureBirb(t, cfg, repo); err == nil {
		t.Error("EnsureBirb accepted an empty birb.user")
	}
}