-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcache.go
158 lines (136 loc) · 3.51 KB
/
cache.go
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
146
147
148
149
150
151
152
153
154
155
156
157
158
package atum
import (
"fmt"
"log"
"os"
"os/user"
"path"
"sync"
"time"
"github.com/timshannon/bolthold"
bolt "go.etcd.io/bbolt"
)
var (
cache Cache
)
// Set the cache used by the Atum client to store server info and public keys.
//
// See the Cache interface.
func SetCache(newCache Cache) {
cache = newCache
}
// Caches for each known Atum server its public keys (for faster verification)
// and the ServerInfo (for faster stamping).
type Cache interface {
// Caches that the given public key is valid for the server
StorePublicKey(serverUrl string, alg SignatureAlgorithm,
pk []byte, expires time.Time)
// Returns until when this public key should be trusted for the given
// server (and nil if the public key is not to be trusted).
GetPublicKey(serverUrl string, alg SignatureAlgorithm, pk []byte) *time.Time
// Caches the server information.
StoreServerInfo(serverUrl string, info ServerInfo)
// Retreieves cached server information, if available.
GetServerInfo(serverUrl string) *ServerInfo
}
func init() {
cache = &boltCache{}
}
type boltCache struct {
mux sync.Mutex
db *bolthold.Store
path string
}
func pkKey(serverUrl string, alg SignatureAlgorithm, pk []byte) string {
return fmt.Sprintf("%x-%s-%s", pk, alg, serverUrl)
}
func (cache *boltCache) exit() {
if cache.db != nil {
if err := cache.db.Close(); err != nil {
log.Printf("atum cache: %v", err)
}
cache.db = nil
}
cache.mux.Unlock()
}
func (cache *boltCache) enter(write bool) bool {
cache.mux.Lock()
if cache.path == "" {
usr, err := user.Current()
if err != nil {
log.Printf("atum cache: user.Current(): %v", err)
cache.mux.Unlock()
return false
}
cacheDirPath := path.Join(usr.HomeDir, ".cache", "atum")
if _, err = os.Stat(cacheDirPath); os.IsNotExist(err) {
err = os.MkdirAll(cacheDirPath, 0700)
if err != nil {
log.Printf("atum cache: os.MkdirAll(%s): %v", cacheDirPath, err)
cache.mux.Unlock()
return false
}
}
cache.path = path.Join(cacheDirPath, "cache.bolt")
}
var err error
cache.db, err = bolthold.Open(cache.path, 0600, &bolthold.Options{
Options: &bolt.Options{
ReadOnly: !write,
},
})
if err != nil {
log.Printf("atum cache: bolthold.Open(%s): %v", cache.path, err)
cache.mux.Unlock()
return false
}
return true
}
func (cache *boltCache) StorePublicKey(serverUrl string, alg SignatureAlgorithm,
pk []byte, expires time.Time) {
if !cache.enter(true) {
return
}
defer cache.exit()
if err := cache.db.Upsert(pkKey(serverUrl, alg, pk), &expires); err != nil {
log.Printf("atum cache: StorePublicKey(): %v", err)
}
}
func (cache *boltCache) GetPublicKey(serverUrl string,
alg SignatureAlgorithm, pk []byte) *time.Time {
if !cache.enter(false) {
return nil
}
defer cache.exit()
var ret time.Time
if err := cache.db.Get(pkKey(serverUrl, alg, pk), &ret); err != nil {
if err != bolthold.ErrNotFound {
log.Printf("atum cache: GetPublicKey(): %v", err)
}
return nil
}
return &ret
}
func (cache *boltCache) StoreServerInfo(serverUrl string, info ServerInfo) {
if !cache.enter(true) {
return
}
defer cache.exit()
if err := cache.db.Upsert(serverUrl, &info); err != nil {
log.Printf("atum cache: StoreServerInfo(): %v", err)
}
}
func (cache *boltCache) GetServerInfo(serverUrl string) *ServerInfo {
if !cache.enter(false) {
return nil
}
defer cache.exit()
var ret ServerInfo
if err := cache.db.Get(serverUrl, &ret); err != nil {
if err != bolthold.ErrNotFound {
log.Printf("atum cache: GetServerInfo(): %v", err)
}
return nil
}
return &ret
}