@cryptotaxi247 / kubo / commits / abefd93fb

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