init.go 3.93 KB
Newer Older
1
package main
Matt Bell's avatar
Matt Bell committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

import (
	"encoding/base64"
	"errors"
	"os"
	"path/filepath"

	cmds "github.com/jbenet/go-ipfs/commands"
	config "github.com/jbenet/go-ipfs/config"
	ci "github.com/jbenet/go-ipfs/crypto"
	peer "github.com/jbenet/go-ipfs/peer"
	updates "github.com/jbenet/go-ipfs/updates"
	u "github.com/jbenet/go-ipfs/util"
)

var initCmd = &cmds.Command{
	Options: []cmds.Option{
		cmds.Option{[]string{"bits", "b"}, cmds.Int},
		cmds.Option{[]string{"passphrase", "p"}, cmds.String},
		cmds.Option{[]string{"force", "f"}, cmds.Bool},
		cmds.Option{[]string{"datastore", "d"}, cmds.String},
	},
	Help: `ipfs init

  Initializes ipfs configuration files and generates a
  new keypair.
`,
	Run: func(res cmds.Response, req cmds.Request) {
		ctx := req.Context()

		u.POut("initializing ipfs node at %s\n", ctx.ConfigRoot)
		filename, err := config.Filename(ctx.ConfigRoot)
		if err != nil {
			res.SetError(errors.New("Couldn't get home directory path"), cmds.ErrNormal)
			return
		}

		arg, found := req.Option("d")
		dspath, ok := arg.(string)
		if found && !ok {
			res.SetError(errors.New("failed to parse datastore flag"), cmds.ErrNormal)
			return
		}

		fi, err := os.Lstat(filename)
		arg, found = req.Option("f")
		force, ok := arg.(bool)
		if found && !ok {
			res.SetError(errors.New("failed to parse force flag"), cmds.ErrNormal)
			return
		}
		if fi != nil || (err != nil && !os.IsNotExist(err)) {
			if !force {
				res.SetError(errors.New("ipfs configuration file already exists!\nReinitializing would overwrite your keys.\n(use -f to force overwrite)"), cmds.ErrNormal)
				return
			}
		}
		cfg := new(config.Config)

		cfg.Datastore = config.Datastore{}
		if len(dspath) == 0 {
			dspath, err = config.DataStorePath("")
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
		}
		cfg.Datastore.Path = dspath
		cfg.Datastore.Type = "leveldb"

		// Construct the data store if missing
		if err := os.MkdirAll(dspath, os.ModePerm); err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		// Check the directory is writeable
		if f, err := os.Create(filepath.Join(dspath, "._check_writeable")); err == nil {
			os.Remove(f.Name())
		} else {
			res.SetError(errors.New("Datastore '"+dspath+"' is not writeable"), cmds.ErrNormal)
			return
		}

		cfg.Identity = config.Identity{}

		// setup the node addresses.
		cfg.Addresses = config.Addresses{
			Swarm: "/ip4/0.0.0.0/tcp/4001",
			API:   "/ip4/127.0.0.1/tcp/5001",
		}

		// setup the node mount points.
		cfg.Mounts = config.Mounts{
			IPFS: "/ipfs",
			IPNS: "/ipns",
		}

		arg, found = req.Option("b")
		nbits, ok := arg.(int)
		if found && !ok {
			res.SetError(errors.New("failed to get bits flag"), cmds.ErrNormal)
			return
		} else if !found {
			nbits = 4096
		}
		if nbits < 1024 {
			res.SetError(errors.New("Bitsize less than 1024 is considered unsafe."), cmds.ErrNormal)
			return
		}

		u.POut("generating key pair\n")
		sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		// currently storing key unencrypted. in the future we need to encrypt it.
		// TODO(security)
		skbytes, err := sk.Bytes()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		cfg.Identity.PrivKey = base64.StdEncoding.EncodeToString(skbytes)

		id, err := peer.IDFromPubKey(pk)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		cfg.Identity.PeerID = id.Pretty()

		// Use these hardcoded bootstrap peers for now.
		cfg.Bootstrap = []*config.BootstrapPeer{
			&config.BootstrapPeer{
				// mars.i.ipfs.io
				PeerID:  "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
				Address: "/ip4/104.131.131.82/tcp/4001",
			},
		}

		// tracking ipfs version used to generate the init folder and adding update checker default setting.
		cfg.Version = config.Version{
			Check:   "error",
			Current: updates.Version,
		}

		err = config.WriteConfigFile(filename, cfg)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
	},
}