-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #144 from jbenet/bootstrap-cmd
bootstrap cmd
- Loading branch information
Showing
3 changed files
with
281 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"strings" | ||
|
||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" | ||
"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" | ||
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" | ||
|
||
config "github.com/jbenet/go-ipfs/config" | ||
peer "github.com/jbenet/go-ipfs/peer" | ||
u "github.com/jbenet/go-ipfs/util" | ||
) | ||
|
||
var cmdIpfsBootstrap = &commander.Command{ | ||
UsageLine: "bootstrap", | ||
Short: "Show a list of bootstrapped addresses.", | ||
Long: `ipfs bootstrap - show, or manipulate bootstrap node addresses | ||
Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'. | ||
Commands: | ||
list Show the boostrap list. | ||
add <address> Add a node's address to the bootstrap list. | ||
remove <address> Remove an address from the bootstrap list. | ||
` + bootstrapSecurityWarning, | ||
Run: bootstrapListCmd, | ||
Subcommands: []*commander.Command{ | ||
cmdIpfsBootstrapRemove, | ||
cmdIpfsBootstrapAdd, | ||
cmdIpfsBootstrapList, | ||
}, | ||
Flag: *flag.NewFlagSet("ipfs-bootstrap", flag.ExitOnError), | ||
} | ||
|
||
var cmdIpfsBootstrapRemove = &commander.Command{ | ||
UsageLine: "remove <address | peerid>", | ||
Short: "Remove addresses from the bootstrap list.", | ||
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{ | ||
UsageLine: "add <address | peerid>", | ||
Short: "Add addresses to the bootstrap list.", | ||
Long: `ipfs bootstrap add - add addresses to the bootstrap list | ||
` + bootstrapSecurityWarning, | ||
Run: bootstrapAddCmd, | ||
Flag: *flag.NewFlagSet("ipfs-bootstrap-add", flag.ExitOnError), | ||
} | ||
|
||
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 { | ||
return errors.New("remove: no address or peerid specified") | ||
} | ||
|
||
toRemove, err := bootstrapInputToPeers(inp) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
cfg, err := getConfig(c) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
keep := []*config.BootstrapPeer{} | ||
remove := []*config.BootstrapPeer{} | ||
|
||
// function to filer what to keep | ||
shouldKeep := func(bp *config.BootstrapPeer) bool { | ||
for _, skipBP := range toRemove { | ||
|
||
// IDs must match to skip. | ||
if bp.PeerID != skipBP.PeerID { | ||
continue | ||
} | ||
|
||
// if Addresses match, or skipBP has no addr (wildcard) | ||
if skipBP.Address == bp.Address || skipBP.Address == "" { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// filter all the existing peers | ||
for _, currBP := range cfg.Bootstrap { | ||
if shouldKeep(currBP) { | ||
keep = append(keep, currBP) | ||
} else { | ||
remove = append(remove, currBP) | ||
} | ||
} | ||
|
||
// if didn't remove anyone, bail. | ||
if len(keep) == len(cfg.Bootstrap) { | ||
return errors.New("remove: peer given did not match any in list") | ||
} | ||
|
||
// write new config | ||
cfg.Bootstrap = keep | ||
if err := writeConfig(c, cfg); err != nil { | ||
return err | ||
} | ||
|
||
for _, bp := range remove { | ||
u.POut("removed %s\n", bp) | ||
} | ||
return nil | ||
} | ||
|
||
func bootstrapAddCmd(c *commander.Command, inp []string) error { | ||
|
||
if len(inp) == 0 { | ||
return errors.New("add: no address specified") | ||
} | ||
|
||
toAdd, err := bootstrapInputToPeers(inp) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
cfg, err := getConfig(c) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// function to check whether a peer is already in the list. | ||
combine := func(lists ...[]*config.BootstrapPeer) []*config.BootstrapPeer { | ||
|
||
set := map[string]struct{}{} | ||
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 | ||
} | ||
|
||
// combine both lists, removing dups. | ||
cfg.Bootstrap = combine(cfg.Bootstrap, toAdd) | ||
if err := writeConfig(c, cfg); err != nil { | ||
return err | ||
} | ||
|
||
for _, bp := range toAdd { | ||
u.POut("added %s\n", bp) | ||
} | ||
return nil | ||
} | ||
|
||
func bootstrapListCmd(c *commander.Command, inp []string) error { | ||
|
||
cfg, err := getConfig(c) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, bp := range cfg.Bootstrap { | ||
u.POut("%s\n", bp) | ||
} | ||
|
||
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. | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters