1package autotls
2
3import (
4 "context"
5 "crypto"
6 "errors"
7 "fmt"
8 "os"
9 "reflect"
10 "testing"
11
12 "github.com/mjl-/autocert"
13
14 "github.com/mjl-/mox/dns"
15 "github.com/mjl-/mox/mlog"
16)
17
18func TestAutotls(t *testing.T) {
19 log := mlog.New("autotls", nil)
20 os.RemoveAll("../testdata/autotls")
21 os.MkdirAll("../testdata/autotls", 0770)
22
23 shutdown := make(chan struct{})
24
25 getPrivateKey := func(host string, keyType autocert.KeyType) (crypto.Signer, error) {
26 return nil, fmt.Errorf("not used")
27 }
28 m, err := Load("test", "../testdata/autotls", "mox@localhost", "https://localhost/", "", nil, getPrivateKey, shutdown)
29 if err != nil {
30 t.Fatalf("load manager: %v", err)
31 }
32 l := m.Hostnames()
33 if len(l) != 0 {
34 t.Fatalf("hostnames, got %v, expected empty list", l)
35 }
36 if err := m.HostPolicy(context.Background(), "mox.example"); err == nil || !errors.Is(err, errHostNotAllowed) {
37 t.Fatalf("hostpolicy, got err %v, expected errHostNotAllowed", err)
38 }
39 m.SetAllowedHostnames(log, dns.MockResolver{}, map[dns.Domain]struct{}{{ASCII: "mox.example"}: {}}, nil, false)
40 l = m.Hostnames()
41 if !reflect.DeepEqual(l, []dns.Domain{{ASCII: "mox.example"}}) {
42 t.Fatalf("hostnames, got %v, expected single mox.example", l)
43 }
44 if err := m.HostPolicy(context.Background(), "mox.example"); err != nil {
45 t.Fatalf("hostpolicy, got err %v, expected no error", err)
46 }
47 if err := m.HostPolicy(context.Background(), "mox.example:80"); err != nil {
48 t.Fatalf("hostpolicy, got err %v, expected no error", err)
49 }
50 if err := m.HostPolicy(context.Background(), "other.mox.example"); err == nil || !errors.Is(err, errHostNotAllowed) {
51 t.Fatalf("hostpolicy, got err %v, expected errHostNotAllowed", err)
52 }
53
54 ctx := context.Background()
55 cache := m.Manager.Cache
56 if _, err := cache.Get(ctx, "mox.example"); err == nil || !errors.Is(err, autocert.ErrCacheMiss) {
57 t.Fatalf("cache get for absent entry: got err %v, expected autocert.ErrCacheMiss", err)
58 }
59 if err := cache.Put(ctx, "mox.example", []byte("test")); err != nil {
60 t.Fatalf("cache put for absent entry: got err %v, expected error", err)
61 }
62 if data, err := cache.Get(ctx, "mox.example"); err != nil || string(data) != "test" {
63 t.Fatalf("cache get: got err %v data %q, expected nil, 'test'", err, data)
64 }
65 if err := cache.Put(ctx, "mox.example", []byte("test2")); err != nil {
66 t.Fatalf("cache put for absent entry: got err %v, expected error", err)
67 }
68 if data, err := cache.Get(ctx, "mox.example"); err != nil || string(data) != "test2" {
69 t.Fatalf("cache get: got err %v data %q, expected nil, 'test2'", err, data)
70 }
71 if err := cache.Delete(ctx, "mox.example"); err != nil {
72 t.Fatalf("cache delete: got err %v, expected no error", err)
73 }
74 if _, err := cache.Get(ctx, "mox.example"); err == nil || !errors.Is(err, autocert.ErrCacheMiss) {
75 t.Fatalf("cache get for absent entry: got err %v, expected autocert.ErrCacheMiss", err)
76 }
77
78 close(shutdown)
79 if err := m.HostPolicy(context.Background(), "mox.example"); err == nil {
80 t.Fatalf("hostpolicy, got err %v, expected error due to shutdown", err)
81 }
82
83 key0 := m.Manager.Client.Key
84
85 m, err = Load("test", "../testdata/autotls", "mox@localhost", "https://localhost/", "", nil, getPrivateKey, shutdown)
86 if err != nil {
87 t.Fatalf("load manager again: %v", err)
88 }
89 if !reflect.DeepEqual(m.Manager.Client.Key, key0) {
90 t.Fatalf("private key changed after reload")
91 }
92 m.shutdown = make(chan struct{})
93 m.SetAllowedHostnames(log, dns.MockResolver{}, map[dns.Domain]struct{}{{ASCII: "mox.example"}: {}}, nil, false)
94 if err := m.HostPolicy(context.Background(), "mox.example"); err != nil {
95 t.Fatalf("hostpolicy, got err %v, expected no error", err)
96 }
97
98 m2, err := Load("test2", "../testdata/autotls", "mox@localhost", "https://localhost/", "", nil, nil, shutdown)
99 if err != nil {
100 t.Fatalf("load another manager: %v", err)
101 }
102 if reflect.DeepEqual(m.Manager.Client.Key, m2.Manager.Client.Key) {
103 t.Fatalf("private key reused between managers")
104 }
105
106 // Only remove in case of success.
107 os.RemoveAll("../testdata/autotls")
108}
109