-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathrepo.go
259 lines (212 loc) · 6.89 KB
/
repo.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
package encrepo
import (
"context"
"fmt"
"net"
"github.com/ipfs/boxo/filestore"
"github.com/ipfs/boxo/keystore"
"github.com/ipfs/go-datastore"
config "github.com/ipfs/kubo/config"
"github.com/ipfs/kubo/repo"
"github.com/ipfs/kubo/repo/common"
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/pkg/errors"
)
type encRepo struct {
root datastore.Datastore
ds repo.Datastore
ks keystore.Keystore
config *config.Config
closed bool
}
var _ repo.Repo = (*encRepo)(nil)
// Config returns the ipfs configuration file from the repo. Changes made
// to the returned config are not automatically persisted.
func (r *encRepo) Config() (*config.Config, error) {
packageLock.Lock()
defer packageLock.Unlock()
if r.closed {
return nil, errors.New("cannot access config, repo not open")
}
return r.config, nil
}
// BackupConfig creates a backup of the current configuration file using
// the given prefix for naming.
func (r *encRepo) BackupConfig(prefix string) (string, error) {
// Not implemented since the implementation of this in fsrepo makes no sense
// The backup file name is randomly generated within the function but not returned, so it's not possible to find the backup file afterwards
return "", errors.New("not implemented")
}
// SetGatewayAddr sets the Gateway address in the repo.
func (r *encRepo) SetGatewayAddr(addr net.Addr) error {
packageLock.Lock()
defer packageLock.Unlock()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
m, err := manet.FromNetAddr(addr)
if err != nil {
return fmt.Errorf("unable to parse addr `%s` to multiaddr: %w", m.String(), err)
}
bytes, err := m.MarshalBinary()
if err != nil {
return errors.Wrap(err, "marshal ma")
}
key := datastore.NewKey("gateway")
if err := r.root.Put(ctx, key, bytes); err != nil {
return errors.Wrap(err, fmt.Sprintf("put '%s' in ds", key))
}
return nil
}
// SetConfig persists the given configuration struct to storage.
func (r *encRepo) SetConfig(updated *config.Config) error {
packageLock.Lock()
defer packageLock.Unlock()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
return r.setConfig(ctx, updated)
}
// SetConfig persists the given configuration struct to storage.
func (r *encRepo) setConfig(ctx context.Context, updated *config.Config) error {
// to avoid clobbering user-provided keys, must read the config from disk
// as a map, write the updated struct values to the map and write the map
// to disk.
var mapconf map[string]interface{}
if err := readConfigFromDatastore(ctx, r.root, &mapconf); err != nil {
return err
}
m, err := config.ToMap(updated)
if err != nil {
return err
}
for k, v := range m {
mapconf[k] = v
}
// Do not use `*r.config = ...`. This will modify the *shared* config
// returned by `r.Config`.
conf, err := config.FromMap(mapconf)
if err != nil {
return err
}
if err := writeConfigToDatastore(ctx, r.root, conf); err != nil {
return err
}
r.config = conf
return nil
}
// SetConfigKey sets the given key-value pair within the config and persists it to storage.
func (r *encRepo) SetConfigKey(key string, value interface{}) error {
packageLock.Lock()
defer packageLock.Unlock()
if r.closed {
return errors.New("repo is closed")
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Load into a map so we don't end up writing any additional defaults to the config file.
var mapconf map[string]interface{}
if err := readConfigFromDatastore(ctx, r.root, &mapconf); err != nil {
return err
}
// Load private key to guard against it being overwritten.
// NOTE: this is a temporary measure to secure this field until we move
// keys out of the config file.
pkval, err := common.MapGetKV(mapconf, config.PrivKeySelector)
if err != nil {
return err
}
// Set the key in the map.
if err := common.MapSetKV(mapconf, key, value); err != nil {
return err
}
// replace private key, in case it was overwritten.
if err := common.MapSetKV(mapconf, config.PrivKeySelector, pkval); err != nil {
return err
}
// This step doubles as to validate the map against the struct
// before serialization
conf, err := config.FromMap(mapconf)
if err != nil {
return err
}
// Write config
return r.setConfig(ctx, conf)
}
// GetConfigKey reads the value for the given key from the configuration in storage.
func (r *encRepo) GetConfigKey(key string) (interface{}, error) {
packageLock.Lock()
defer packageLock.Unlock()
if r.closed {
return nil, errors.New("repo is closed")
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var cfg map[string]interface{}
if err := readConfigFromDatastore(ctx, r.root, &cfg); err != nil {
return nil, err
}
return common.MapGetKV(cfg, key)
}
// Datastore returns a reference to the configured data storage backend.
func (r *encRepo) Datastore() repo.Datastore {
return r.ds
}
// GetStorageUsage returns the number of bytes stored.
func (r *encRepo) GetStorageUsage(ctx context.Context) (uint64, error) {
return datastore.DiskUsage(ctx, r.Datastore())
}
// Keystore returns a reference to the key management interface.
func (r *encRepo) Keystore() keystore.Keystore {
return r.ks
}
// FileManager returns a reference to the filestore file manager.
func (r *encRepo) FileManager() *filestore.FileManager {
return nil
}
// SetAPIAddr sets the API address in the repo.
func (r *encRepo) SetAPIAddr(addr ma.Multiaddr) error {
packageLock.Lock()
defer packageLock.Unlock()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
bytes, err := addr.MarshalBinary()
if err != nil {
return errors.Wrap(err, "marshal ma")
}
key := datastore.NewKey("api")
if err := r.root.Put(ctx, key, bytes); err != nil {
return errors.Wrap(err, fmt.Sprintf("put '%s' in ds", key))
}
return nil
}
// SwarmKey returns the configured shared symmetric key for the private networks feature.
func (r *encRepo) SwarmKey() ([]byte, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
swarmKey, err := r.root.Get(ctx, datastore.NewKey("swarm.key"))
switch err {
case nil:
return swarmKey, nil
case datastore.ErrNotFound:
return nil, nil
default:
return nil, err
}
}
func (r *encRepo) Close() error {
packageLock.Lock()
defer packageLock.Unlock()
if r.closed {
return errors.New("repo is already closed")
}
r.closed = true
return r.root.Close()
}
func (r *encRepo) UserResourceOverrides() (rcmgr.PartialLimitConfig, error) {
// @NOTE(gfanton): this method is a noop for the moment, but we can use a
// system similar that the one in `ipfs/fsrepo` by using a file or environments
// variables. cf. https://github.com/ipfs/kubo/blob/353dd49be239be651650c3ef3dfef83deebac58c/repo/fsrepo/fsrepo.go#L446
// this method is only here to fullfil the `repo.Repo` interface
return rcmgr.PartialLimitConfig{}, nil
}