Commit abefd93f authored by Juan Batiz-Benet's avatar Juan Batiz-Benet

edited bootstrap cmd

- safer parsing
- multiple inputs
- add: dup detection
- common cfg writing
parent 091f6f85
package main package main
import ( import (
"fmt" "errors"
"strings"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
config "github.com/jbenet/go-ipfs/config" config "github.com/jbenet/go-ipfs/config"
"strings" peer "github.com/jbenet/go-ipfs/peer"
u "github.com/jbenet/go-ipfs/util"
) )
var cmdIpfsBootstrap = &commander.Command{ var cmdIpfsBootstrap = &commander.Command{
...@@ -14,165 +19,236 @@ var cmdIpfsBootstrap = &commander.Command{ ...@@ -14,165 +19,236 @@ var cmdIpfsBootstrap = &commander.Command{
Short: "Show a list of bootstrapped addresses.", Short: "Show a list of bootstrapped addresses.",
Long: `ipfs bootstrap - show, or manipulate bootstrap node addresses Long: `ipfs bootstrap - show, or manipulate bootstrap node addresses
SECURITY WARNING:
The bootstrap command manipulates the "bootstrap list", which contains
the addresses of bootstrap nodes. These are the *trusted peers* from
which to learn about other peers in the network. Only edit this list
if you understand the risks of adding or removing nodes from this list.
Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'. Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'.
Commands: Commands:
list Show the boostrap list. list Show the boostrap list.
add <address> Add a node's address to the bootstrap list. add <address> Add a node's address to the bootstrap list.
remove <address> Remove an address from the bootstrap list. remove <address> Remove an address from the bootstrap list.
`, ` + bootstrapSecurityWarning,
Run: bootstrapCmd, Run: bootstrapListCmd,
Subcommands: []*commander.Command{ Subcommands: []*commander.Command{
cmdIpfsBootstrapRemove, cmdIpfsBootstrapRemove,
cmdIpfsBootstrapAdd, cmdIpfsBootstrapAdd,
cmdIpfsBootstrapList,
}, },
Flag: *flag.NewFlagSet("ipfs-bootstrap", flag.ExitOnError), Flag: *flag.NewFlagSet("ipfs-bootstrap", flag.ExitOnError),
} }
var cmdIpfsBootstrapRemove = &commander.Command{ var cmdIpfsBootstrapRemove = &commander.Command{
UsageLine: "remove", UsageLine: "remove <address | peerid>",
Run: IpfsBootstrapRemoveCmd, Short: "Remove addresses from the bootstrap list.",
Flag: *flag.NewFlagSet("ipfs-bootstrap-remove", flag.ExitOnError), Long: `ipfs bootstrap remove - remove addresses from the bootstrap list
` + bootstrapSecurityWarning,
Run: bootstrapRemoveCmd,
Flag: *flag.NewFlagSet("ipfs-bootstrap-remove", flag.ExitOnError),
} }
var cmdIpfsBootstrapAdd = &commander.Command{ var cmdIpfsBootstrapAdd = &commander.Command{
UsageLine: "add", UsageLine: "add <address | peerid>",
Run: IpfsBootstrapAddCmd, Short: "Add addresses to the bootstrap list.",
Flag: *flag.NewFlagSet("ipfs-bootstrap-add", flag.ExitOnError), Long: `ipfs bootstrap add - add addresses to the bootstrap list
` + bootstrapSecurityWarning,
Run: bootstrapAddCmd,
Flag: *flag.NewFlagSet("ipfs-bootstrap-add", flag.ExitOnError),
} }
func IpfsBootstrapRemoveCmd(c *commander.Command, inp []string) error { var cmdIpfsBootstrapList = &commander.Command{
UsageLine: "list",
Short: "Show addresses in the bootstrap list.",
Run: bootstrapListCmd,
Flag: *flag.NewFlagSet("ipfs-bootstrap-list", flag.ExitOnError),
}
func bootstrapRemoveCmd(c *commander.Command, inp []string) error {
if len(inp) == 0 { if len(inp) == 0 {
fmt.Println("No peer specified.") return errors.New("remove: no address or peerid specified")
return nil
} }
if strings.Contains(inp[0], "/") { toRemove, err := bootstrapInputToPeers(inp)
if err != nil {
return err
}
var pID = inp[0][len(inp[0])-46:] cfg, err := getConfig(c)
var ip = strings.TrimSuffix(inp[0], pID) if err != nil {
maddr, err := ma.NewMultiaddr(strings.TrimSuffix(ip, "/")) return err
var address, _ = maddr.String() }
if err != nil {
return err
}
peer := config.BootstrapPeer{ keep := []*config.BootstrapPeer{}
Address: address, remove := []*config.BootstrapPeer{}
PeerID: pID,
}
configpath, _ := config.Filename("~/.go-ipfs/config") // function to filer what to keep
var cfg config.Config shouldKeep := func(bp *config.BootstrapPeer) bool {
readErr := config.ReadConfigFile(configpath, &cfg) for _, skipBP := range toRemove {
if readErr != nil {
return readErr
}
i := 0 // IDs must match to skip.
for _, v := range cfg.Bootstrap { if bp.PeerID != skipBP.PeerID {
if v.PeerID == peer.PeerID && v.Address == peer.Address {
continue continue
} }
cfg.Bootstrap[i] = v
i++
}
cfg.Bootstrap = cfg.Bootstrap[:i]
writeErr := config.WriteConfigFile(configpath, cfg) // if Addresses match, or skipBP has no addr (wildcard)
if writeErr != nil { if skipBP.Address == bp.Address || skipBP.Address == "" {
return writeErr return false
}
} }
return true
} }
if !strings.Contains(inp[0], "/") { // filter all the existing peers
for _, currBP := range cfg.Bootstrap {
var peerID = inp[0] if shouldKeep(currBP) {
keep = append(keep, currBP)
configpath, _ := config.Filename("~/.go-ipfs/config") } else {
var cfg config.Config remove = append(remove, currBP)
readErr := config.ReadConfigFile(configpath, &cfg)
if readErr != nil {
return readErr
} }
}
i := 0 // if didn't remove anyone, bail.
for _, v := range cfg.Bootstrap { if len(keep) == len(cfg.Bootstrap) {
if v.PeerID == peerID { return errors.New("remove: peer given did not match any in list")
continue }
}
cfg.Bootstrap[i] = v
i++
}
cfg.Bootstrap = cfg.Bootstrap[:i]
writeErr := config.WriteConfigFile(configpath, cfg) // write new config
if writeErr != nil { cfg.Bootstrap = keep
return writeErr if err := writeConfig(c, cfg); err != nil {
} return err
}
for _, bp := range remove {
u.POut("removed %s\n", bp)
} }
return nil return nil
} }
func IpfsBootstrapAddCmd(c *commander.Command, inp []string) error { func bootstrapAddCmd(c *commander.Command, inp []string) error {
if len(inp) == 0 { if len(inp) == 0 {
fmt.Println("No peer specified.") return errors.New("add: no address specified")
return nil
} }
var pID = inp[0][len(inp[0])-46:] toAdd, err := bootstrapInputToPeers(inp)
var ip = strings.TrimSuffix(inp[0], pID)
maddr, err := ma.NewMultiaddr(strings.TrimSuffix(ip, "/"))
var address, _ = maddr.String()
if err != nil { if err != nil {
return err return err
} }
peer := config.BootstrapPeer{ cfg, err := getConfig(c)
Address: address, if err != nil {
PeerID: pID, return err
} }
configpath, _ := config.Filename("~/.go-ipfs/config") // function to check whether a peer is already in the list.
var cfg config.Config combine := func(lists ...[]*config.BootstrapPeer) []*config.BootstrapPeer {
readErr := config.ReadConfigFile(configpath, &cfg)
if readErr != nil { set := map[string]struct{}{}
return readErr final := []*config.BootstrapPeer{}
for _, list := range lists {
for _, peer := range list {
// if already in the set, continue
_, found := set[peer.String()]
if found {
continue
}
set[peer.String()] = struct{}{}
final = append(final, peer)
}
}
return final
} }
addedPeer := append(cfg.Bootstrap, &peer) // combine both lists, removing dups.
cfg.Bootstrap = addedPeer cfg.Bootstrap = combine(cfg.Bootstrap, toAdd)
if err := writeConfig(c, cfg); err != nil {
return err
}
writeErr := config.WriteConfigFile(configpath, cfg) for _, bp := range toAdd {
if writeErr != nil { u.POut("added %s\n", bp)
return writeErr
} }
return nil return nil
return nil
} }
func bootstrapCmd(c *commander.Command, inp []string) error {
configpath, _ := config.Filename("~/.go-ipfs/config") func bootstrapListCmd(c *commander.Command, inp []string) error {
var cfg config.Config
config.ReadConfigFile(configpath, &cfg)
for i := range cfg.Bootstrap { cfg, err := getConfig(c)
s := []string{cfg.Bootstrap[i].Address, "/", cfg.Bootstrap[i].PeerID, "\n"} if err != nil {
fmt.Printf(strings.Join(s, "")) return err
}
for _, bp := range cfg.Bootstrap {
u.POut("%s\n", bp)
} }
return nil return nil
}
func writeConfig(c *commander.Command, cfg *config.Config) error {
confdir, err := getConfigDir(c)
if err != nil {
return err
}
filename, err := config.Filename(confdir)
if err != nil {
return err
}
return config.WriteConfigFile(filename, cfg)
} }
func bootstrapInputToPeers(input []string) ([]*config.BootstrapPeer, error) {
split := func(addr string) (string, string) {
idx := strings.LastIndex(addr, "/")
if idx == -1 {
return "", addr
}
return addr[:idx], addr[idx+1:]
}
peers := []*config.BootstrapPeer{}
for _, addr := range input {
addrS, peeridS := split(addr)
// make sure addrS parses as a multiaddr.
if len(addrS) > 0 {
maddr, err := ma.NewMultiaddr(addrS)
if err != nil {
return nil, err
}
addrS, err = maddr.String()
if err != nil {
return nil, err
}
}
// make sure idS parses as a peer.ID
peerid, err := mh.FromB58String(peeridS)
if err != nil {
return nil, err
}
// construct config entry
peers = append(peers, &config.BootstrapPeer{
Address: addrS,
PeerID: peer.ID(peerid).Pretty(),
})
}
return peers, nil
}
const bootstrapSecurityWarning = `
SECURITY WARNING:
The bootstrap command manipulates the "bootstrap list", which contains
the addresses of bootstrap nodes. These are the *trusted peers* from
which to learn about other peers in the network. Only edit this list
if you understand the risks of adding or removing nodes from this list.
`
...@@ -35,6 +35,10 @@ type BootstrapPeer struct { ...@@ -35,6 +35,10 @@ type BootstrapPeer struct {
PeerID string // until multiaddr supports ipfs, use another field. PeerID string // until multiaddr supports ipfs, use another field.
} }
func (bp *BootstrapPeer) String() string {
return bp.Address + "/" + bp.PeerID
}
// Config is used to load IPFS config files. // Config is used to load IPFS config files.
type Config struct { type Config struct {
Identity Identity // local node's peer identity Identity Identity // local node's peer identity
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment