mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-25 06:58:18 +08:00
Merge branch 'master' into ipns
Conflicts: cmd/ipfs/ipfs.go
This commit is contained in:
251
cmd/ipfs/bootstrap.go
Normal file
251
cmd/ipfs/bootstrap.go
Normal file
@ -0,0 +1,251 @@
|
||||
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 = maddr.String()
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
`
|
@ -56,6 +56,7 @@ Use "ipfs help <command>" for more information about a command.
|
||||
cmdIpfsServe,
|
||||
cmdIpfsRun,
|
||||
cmdIpfsName,
|
||||
cmdIpfsBootstrap,
|
||||
},
|
||||
Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
|
||||
}
|
||||
@ -122,23 +123,32 @@ func localNode(confdir string, online bool) (*core.IpfsNode, error) {
|
||||
// Gets the config "-c" flag from the command, or returns
|
||||
// the default configuration root directory
|
||||
func getConfigDir(c *commander.Command) (string, error) {
|
||||
root := c
|
||||
for root.Parent != nil {
|
||||
root = root.Parent
|
||||
}
|
||||
conf := root.Flag.Lookup("c").Value.Get()
|
||||
if conf == nil {
|
||||
return config.PathRoot()
|
||||
}
|
||||
confStr, ok := conf.(string)
|
||||
if !ok {
|
||||
return "", errors.New("failed to retrieve config flag value")
|
||||
}
|
||||
if len(confStr) == 0 {
|
||||
return config.PathRoot()
|
||||
|
||||
// use the root cmd (that's where config is specified)
|
||||
for ; c.Parent != nil; c = c.Parent {
|
||||
}
|
||||
|
||||
return u.TildeExpansion(confStr)
|
||||
// flag should be defined on root.
|
||||
param := c.Flag.Lookup("c").Value.Get().(string)
|
||||
if param != "" {
|
||||
return u.TildeExpansion(param)
|
||||
}
|
||||
|
||||
return config.PathRoot()
|
||||
}
|
||||
|
||||
func getConfig(c *commander.Command) (*config.Config, error) {
|
||||
confdir, err := getConfigDir(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filename, err := config.Filename(confdir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config.Load(filename)
|
||||
}
|
||||
|
||||
// cmdContext is a wrapper structure that keeps a node, a daemonlistener, and
|
||||
|
@ -41,6 +41,10 @@ type BootstrapPeer struct {
|
||||
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.
|
||||
type Config struct {
|
||||
Identity Identity // local node's peer identity
|
||||
|
Reference in New Issue
Block a user