edited bootstrap cmd
- safer parsing - multiple inputs - add: dup detection - common cfg writing
Juan Batiz-Benet committed
Oct 6, 2014 at 02:14 UTC
abefd93fb8ed6634d7278dc752670c79514fa24b
2 files changed
+181
-101
cmd/ipfs/bootstrap.go
+177
-101
@@ -1,12 +1,17 @@
1
package main
2
3
import (
4
- "fmt"
4
+ "errors"
5
+ "strings"
6
+
7
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
8
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
9
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10
+ mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
11
+
12
config "github.com/jbenet/go-ipfs/config"
9
- "strings"
13
+ peer "github.com/jbenet/go-ipfs/peer"
14
+ u "github.com/jbenet/go-ipfs/util"
15
)
16
17
var cmdIpfsBootstrap = &commander.Command{
@@ -14,165 +19,236 @@ var cmdIpfsBootstrap = &commander.Command{
19
Short: "Show a list of bootstrapped addresses.",
20
Long: `ipfs bootstrap - show, or manipulate bootstrap node addresses
21
17
-SECURITY WARNING:
18
-
19
-The bootstrap command manipulates the "bootstrap list", which contains
20
-the addresses of bootstrap nodes. These are the *trusted peers* from
21
-which to learn about other peers in the network. Only edit this list
22
-if you understand the risks of adding or removing nodes from this list.
23
-
22
Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'.
23
24
Commands:
25
28
- list Show the boostrap list.
29
- add <address> Add a node's address to the bootstrap list.
30
- remove <address> Remove an address from the bootstrap list.
26
+ list Show the boostrap list.
27
+ add <address> Add a node's address to the bootstrap list.
28
+ remove <address> Remove an address from the bootstrap list.
29
32
-`,
33
- Run: bootstrapCmd,
30
+` + bootstrapSecurityWarning,
31
+ Run: bootstrapListCmd,
32
Subcommands: []*commander.Command{
33
cmdIpfsBootstrapRemove,
34
cmdIpfsBootstrapAdd,
35
+ cmdIpfsBootstrapList,
36
},
37
Flag: *flag.NewFlagSet("ipfs-bootstrap", flag.ExitOnError),
38
}
39
40
var cmdIpfsBootstrapRemove = &commander.Command{
42
- UsageLine: "remove",
43
- Run: IpfsBootstrapRemoveCmd,
44
- Flag: *flag.NewFlagSet("ipfs-bootstrap-remove", flag.ExitOnError),
41
+ UsageLine: "remove <address | peerid>",
42
+ Short: "Remove addresses from the bootstrap list.",
43
+ Long: `ipfs bootstrap remove - remove addresses from the bootstrap list
44
+` + bootstrapSecurityWarning,
45
+ Run: bootstrapRemoveCmd,
46
+ Flag: *flag.NewFlagSet("ipfs-bootstrap-remove", flag.ExitOnError),
47
}
48
49
var cmdIpfsBootstrapAdd = &commander.Command{
48
- UsageLine: "add",
49
- Run: IpfsBootstrapAddCmd,
50
- Flag: *flag.NewFlagSet("ipfs-bootstrap-add", flag.ExitOnError),
50
+ UsageLine: "add <address | peerid>",
51
+ Short: "Add addresses to the bootstrap list.",
52
+ Long: `ipfs bootstrap add - add addresses to the bootstrap list
53
+` + bootstrapSecurityWarning,
54
+ Run: bootstrapAddCmd,
55
+ Flag: *flag.NewFlagSet("ipfs-bootstrap-add", flag.ExitOnError),
56
}
57
53
-func IpfsBootstrapRemoveCmd(c *commander.Command, inp []string) error {
58
+var cmdIpfsBootstrapList = &commander.Command{
59
+ UsageLine: "list",
60
+ Short: "Show addresses in the bootstrap list.",
61
+ Run: bootstrapListCmd,
62
+ Flag: *flag.NewFlagSet("ipfs-bootstrap-list", flag.ExitOnError),
63
+}
64
+
65
+func bootstrapRemoveCmd(c *commander.Command, inp []string) error {
66
67
if len(inp) == 0 {
56
- fmt.Println("No peer specified.")
57
- return nil
68
+ return errors.New("remove: no address or peerid specified")
69
}
70
60
- if strings.Contains(inp[0], "/") {
71
+ toRemove, err := bootstrapInputToPeers(inp)
72
+ if err != nil {
73
+ return err
74
+ }
75
62
- var pID = inp[0][len(inp[0])-46:]
63
- var ip = strings.TrimSuffix(inp[0], pID)
64
- maddr, err := ma.NewMultiaddr(strings.TrimSuffix(ip, "/"))
65
- var address, _ = maddr.String()
66
- if err != nil {
67
- return err
68
- }
76
+ cfg, err := getConfig(c)
77
+ if err != nil {
78
+ return err
79
+ }
80
70
- peer := config.BootstrapPeer{
71
- Address: address,
72
- PeerID: pID,
73
- }
81
+ keep := []*config.BootstrapPeer{}
82
+ remove := []*config.BootstrapPeer{}
83
75
- configpath, _ := config.Filename("~/.go-ipfs/config")
76
- var cfg config.Config
77
- readErr := config.ReadConfigFile(configpath, &cfg)
78
- if readErr != nil {
79
- return readErr
80
- }
84
+ // function to filer what to keep
85
+ shouldKeep := func(bp *config.BootstrapPeer) bool {
86
+ for _, skipBP := range toRemove {
87
82
- i := 0
83
- for _, v := range cfg.Bootstrap {
84
- if v.PeerID == peer.PeerID && v.Address == peer.Address {
88
+ // IDs must match to skip.
89
+ if bp.PeerID != skipBP.PeerID {
90
continue
91
}
87
- cfg.Bootstrap[i] = v
88
- i++
89
- }
90
- cfg.Bootstrap = cfg.Bootstrap[:i]
92
92
- writeErr := config.WriteConfigFile(configpath, cfg)
93
- if writeErr != nil {
94
- return writeErr
93
+ // if Addresses match, or skipBP has no addr (wildcard)
94
+ if skipBP.Address == bp.Address || skipBP.Address == "" {
95
+ return false
96
+ }
97
}
98
+ return true
99
}
100
98
- if !strings.Contains(inp[0], "/") {
99
-
100
- var peerID = inp[0]
101
-
102
- configpath, _ := config.Filename("~/.go-ipfs/config")
103
- var cfg config.Config
104
- readErr := config.ReadConfigFile(configpath, &cfg)
105
- if readErr != nil {
106
- return readErr
101
+ // filter all the existing peers
102
+ for _, currBP := range cfg.Bootstrap {
103
+ if shouldKeep(currBP) {
104
+ keep = append(keep, currBP)
105
+ } else {
106
+ remove = append(remove, currBP)
107
}
108
+ }
109
109
- i := 0
110
- for _, v := range cfg.Bootstrap {
111
- if v.PeerID == peerID {
112
- continue
113
- }
114
- cfg.Bootstrap[i] = v
115
- i++
116
- }
117
- cfg.Bootstrap = cfg.Bootstrap[:i]
110
+ // if didn't remove anyone, bail.
111
+ if len(keep) == len(cfg.Bootstrap) {
112
+ return errors.New("remove: peer given did not match any in list")
113
+ }
114
119
- writeErr := config.WriteConfigFile(configpath, cfg)
120
- if writeErr != nil {
121
- return writeErr
122
- }
115
+ // write new config
116
+ cfg.Bootstrap = keep
117
+ if err := writeConfig(c, cfg); err != nil {
118
+ return err
119
+ }
120
121
+ for _, bp := range remove {
122
+ u.POut("removed %s\n", bp)
123
}
124
return nil
125
}
126
128
-func IpfsBootstrapAddCmd(c *commander.Command, inp []string) error {
127
+func bootstrapAddCmd(c *commander.Command, inp []string) error {
128
129
if len(inp) == 0 {
131
- fmt.Println("No peer specified.")
132
- return nil
130
+ return errors.New("add: no address specified")
131
}
132
135
- var pID = inp[0][len(inp[0])-46:]
136
- var ip = strings.TrimSuffix(inp[0], pID)
137
- maddr, err := ma.NewMultiaddr(strings.TrimSuffix(ip, "/"))
138
- var address, _ = maddr.String()
133
+ toAdd, err := bootstrapInputToPeers(inp)
134
if err != nil {
135
return err
136
}
137
143
- peer := config.BootstrapPeer{
144
- Address: address,
145
- PeerID: pID,
138
+ cfg, err := getConfig(c)
139
+ if err != nil {
140
+ return err
141
}
142
148
- configpath, _ := config.Filename("~/.go-ipfs/config")
149
- var cfg config.Config
150
- readErr := config.ReadConfigFile(configpath, &cfg)
151
- if readErr != nil {
152
- return readErr
143
+ // function to check whether a peer is already in the list.
144
+ combine := func(lists ...[]*config.BootstrapPeer) []*config.BootstrapPeer {
145
+
146
+ set := map[string]struct{}{}
147
+ final := []*config.BootstrapPeer{}
148
+
149
+ for _, list := range lists {
150
+ for _, peer := range list {
151
+ // if already in the set, continue
152
+ _, found := set[peer.String()]
153
+ if found {
154
+ continue
155
+ }
156
+
157
+ set[peer.String()] = struct{}{}
158
+ final = append(final, peer)
159
+ }
160
+ }
161
+ return final
162
}
163
155
- addedPeer := append(cfg.Bootstrap, &peer)
156
- cfg.Bootstrap = addedPeer
164
+ // combine both lists, removing dups.
165
+ cfg.Bootstrap = combine(cfg.Bootstrap, toAdd)
166
+ if err := writeConfig(c, cfg); err != nil {
167
+ return err
168
+ }
169
158
- writeErr := config.WriteConfigFile(configpath, cfg)
159
- if writeErr != nil {
160
- return writeErr
170
+ for _, bp := range toAdd {
171
+ u.POut("added %s\n", bp)
172
}
173
return nil
163
- return nil
174
}
165
-func bootstrapCmd(c *commander.Command, inp []string) error {
175
167
- configpath, _ := config.Filename("~/.go-ipfs/config")
168
- var cfg config.Config
169
- config.ReadConfigFile(configpath, &cfg)
176
+func bootstrapListCmd(c *commander.Command, inp []string) error {
177
171
- for i := range cfg.Bootstrap {
172
- s := []string{cfg.Bootstrap[i].Address, "/", cfg.Bootstrap[i].PeerID, "\n"}
173
- fmt.Printf(strings.Join(s, ""))
178
+ cfg, err := getConfig(c)
179
+ if err != nil {
180
+ return err
181
+ }
182
+
183
+ for _, bp := range cfg.Bootstrap {
184
+ u.POut("%s\n", bp)
185
}
186
187
return nil
188
+}
189
190
+func writeConfig(c *commander.Command, cfg *config.Config) error {
191
+
192
+ confdir, err := getConfigDir(c)
193
+ if err != nil {
194
+ return err
195
+ }
196
+
197
+ filename, err := config.Filename(confdir)
198
+ if err != nil {
199
+ return err
200
+ }
201
+
202
+ return config.WriteConfigFile(filename, cfg)
203
}
204
+
205
+func bootstrapInputToPeers(input []string) ([]*config.BootstrapPeer, error) {
206
+ split := func(addr string) (string, string) {
207
+ idx := strings.LastIndex(addr, "/")
208
+ if idx == -1 {
209
+ return "", addr
210
+ }
211
+ return addr[:idx], addr[idx+1:]
212
+ }
213
+
214
+ peers := []*config.BootstrapPeer{}
215
+ for _, addr := range input {
216
+ addrS, peeridS := split(addr)
217
+
218
+ // make sure addrS parses as a multiaddr.
219
+ if len(addrS) > 0 {
220
+ maddr, err := ma.NewMultiaddr(addrS)
221
+ if err != nil {
222
+ return nil, err
223
+ }
224
+
225
+ addrS, err = maddr.String()
226
+ if err != nil {
227
+ return nil, err
228
+ }
229
+ }
230
+
231
+ // make sure idS parses as a peer.ID
232
+ peerid, err := mh.FromB58String(peeridS)
233
+ if err != nil {
234
+ return nil, err
235
+ }
236
+
237
+ // construct config entry
238
+ peers = append(peers, &config.BootstrapPeer{
239
+ Address: addrS,
240
+ PeerID: peer.ID(peerid).Pretty(),
241
+ })
242
+ }
243
+ return peers, nil
244
+}
245
+
246
+const bootstrapSecurityWarning = `
247
+SECURITY WARNING:
248
+
249
+The bootstrap command manipulates the "bootstrap list", which contains
250
+the addresses of bootstrap nodes. These are the *trusted peers* from
251
+which to learn about other peers in the network. Only edit this list
252
+if you understand the risks of adding or removing nodes from this list.
253
+
254
+`
config/config.go
+4
@@ -35,6 +35,10 @@ type BootstrapPeer struct {
35
PeerID string // until multiaddr supports ipfs, use another field.
36
}
37
38
+func (bp *BootstrapPeer) String() string {
39
+ return bp.Address + "/" + bp.PeerID
40
+}
41
+
42
// Config is used to load IPFS config files.
43
type Config struct {
44
Identity Identity // local node's peer identity