init.go 4.96 KB
Newer Older
1
package main
Matt Bell's avatar
Matt Bell committed
2 3

import (
4
	"bytes"
Matt Bell's avatar
Matt Bell committed
5 6
	"encoding/base64"
	"errors"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
7
	"fmt"
Matt Bell's avatar
Matt Bell committed
8 9 10 11 12
	"os"
	"path/filepath"

	cmds "github.com/jbenet/go-ipfs/commands"
	config "github.com/jbenet/go-ipfs/config"
13
	core "github.com/jbenet/go-ipfs/core"
Matt Bell's avatar
Matt Bell committed
14
	ci "github.com/jbenet/go-ipfs/crypto"
15 16
	imp "github.com/jbenet/go-ipfs/importer"
	chunk "github.com/jbenet/go-ipfs/importer/chunk"
Matt Bell's avatar
Matt Bell committed
17 18 19 20 21
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

var initCmd = &cmds.Command{
22 23 24 25
	Helptext: cmds.HelpText{
		Tagline:          "Initializes IPFS config file",
		ShortDescription: "Initializes IPFS configuration files and generates a new keypair.",
	},
26

Matt Bell's avatar
Matt Bell committed
27
	Options: []cmds.Option{
28
		cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
29 30 31
		cmds.StringOption("passphrase", "p", "Passphrase for encrypting the private key"),
		cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
		cmds.StringOption("datastore", "d", "Location for the IPFS data store"),
Matt Bell's avatar
Matt Bell committed
32
	},
33
	Run: func(req cmds.Request) (interface{}, error) {
34

35
		dspathOverride, _, err := req.Option("d").String() // if !found it's okay. Let == ""
36 37
		if err != nil {
			return nil, err
38 39
		}

40
		force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
41 42
		if err != nil {
			return nil, err
43 44
		}

45
		nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
46 47 48
		if err != nil {
			return nil, err
		}
49
		if !bitsOptFound {
50 51 52
			nBitsForKeypair = 4096
		}

53
		return nil, doInit(req.Context().ConfigRoot, dspathOverride, force, nBitsForKeypair)
54 55
	},
}
Matt Bell's avatar
Matt Bell committed
56

Brian Tiger Chow's avatar
Brian Tiger Chow committed
57
// TODO add default welcome hash: eaa68bedae247ed1e5bd0eb4385a3c0959b976e4
Brian Tiger Chow's avatar
Brian Tiger Chow committed
58 59
// NB: if dspath is not provided, it will be retrieved from the config
func doInit(configRoot string, dspathOverride string, force bool, nBitsForKeypair int) error {
60

61
	u.POut("initializing ipfs node at %s\n", configRoot)
62 63

	configFilename, err := config.Filename(configRoot)
64
	if err != nil {
65
		return errors.New("Couldn't get home directory path")
66 67
	}

68
	fi, err := os.Lstat(configFilename)
69 70
	if fi != nil || (err != nil && !os.IsNotExist(err)) {
		if !force {
71 72
			// TODO multi-line string
			return errors.New("ipfs configuration file already exists!\nReinitializing would overwrite your keys.\n(use -f to force overwrite)")
Matt Bell's avatar
Matt Bell committed
73
		}
74
	}
Matt Bell's avatar
Matt Bell committed
75

Brian Tiger Chow's avatar
Brian Tiger Chow committed
76
	ds, err := datastoreConfig(dspathOverride)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
77
	if err != nil {
78
		return err
79 80
	}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
81 82 83 84
	identity, err := identityConfig(nBitsForKeypair)
	if err != nil {
		return err
	}
85

Brian Tiger Chow's avatar
Brian Tiger Chow committed
86
	conf := config.Config{
87

Brian Tiger Chow's avatar
Brian Tiger Chow committed
88 89 90 91 92 93
		// setup the node addresses.
		Addresses: config.Addresses{
			Swarm: "/ip4/0.0.0.0/tcp/4001",
			API:   "/ip4/127.0.0.1/tcp/5001",
		},

94 95 96 97 98 99 100
		Bootstrap: []*config.BootstrapPeer{
			&config.BootstrapPeer{ // Use these hardcoded bootstrap peers for now.
				// mars.i.ipfs.io
				PeerID:  "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
				Address: "/ip4/104.131.131.82/tcp/4001",
			},
		},
Brian Tiger Chow's avatar
Brian Tiger Chow committed
101 102 103 104

		Datastore: ds,

		Identity: identity,
105

Brian Tiger Chow's avatar
Brian Tiger Chow committed
106 107 108 109 110
		// setup the node mount points.
		Mounts: config.Mounts{
			IPFS: "/ipfs",
			IPNS: "/ipns",
		},
111

Brian Tiger Chow's avatar
Brian Tiger Chow committed
112 113
		// tracking ipfs version used to generate the init folder and adding
		// update checker default setting.
Brian Tiger Chow's avatar
Brian Tiger Chow committed
114
		Version: config.VersionDefaultValue(),
115 116
	}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
117
	err = config.WriteConfigFile(configFilename, conf)
118
	if err != nil {
119
		return err
120
	}
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

	nd, err := core.NewIpfsNode(&conf, false)
	if err != nil {
		return err
	}
	defer nd.Close()

	// Set up default file
	msg := `Hello and Welcome to IPFS!
If you're seeing this, that means that you have successfully
installed ipfs and are now interfacing with the wonderful
world of DAGs and hashes!
`
	reader := bytes.NewBufferString(msg)

	defnd, err := imp.BuildDagFromReader(reader, nd.DAG, nd.Pinning.GetManual(), chunk.DefaultSplitter)
	if err != nil {
		return err
	}

	k, _ := defnd.Key()
	fmt.Printf("Default file key: %s\n", k)

144
	return nil
Matt Bell's avatar
Matt Bell committed
145
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

func datastoreConfig(dspath string) (config.Datastore, error) {
	ds := config.Datastore{}
	if len(dspath) == 0 {
		var err error
		dspath, err = config.DataStorePath("")
		if err != nil {
			return ds, err
		}
	}
	ds.Path = dspath
	ds.Type = "leveldb"

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

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

	return ds, nil
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

func identityConfig(nbits int) (config.Identity, error) {
	// TODO guard higher up
	ident := config.Identity{}
	if nbits < 1024 {
		return ident, errors.New("Bitsize less than 1024 is considered unsafe.")
	}

	fmt.Println("generating key pair...")
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits)
	if err != nil {
		return ident, err
	}

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

	id, err := peer.IDFromPubKey(pk)
	if err != nil {
		return ident, err
	}
	ident.PeerID = id.Pretty()

	return ident, nil
}