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

import (
4
	"bytes"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
5
	"fmt"
6
	"io"
Matt Bell's avatar
Matt Bell committed
7

8
	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9
	assets "github.com/jbenet/go-ipfs/assets"
Matt Bell's avatar
Matt Bell committed
10
	cmds "github.com/jbenet/go-ipfs/commands"
11
	core "github.com/jbenet/go-ipfs/core"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
12
	coreunix "github.com/jbenet/go-ipfs/core/coreunix"
Jeromy's avatar
Jeromy committed
13
	ipns "github.com/jbenet/go-ipfs/fuse/ipns"
14
	config "github.com/jbenet/go-ipfs/repo/config"
15
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
16
	uio "github.com/jbenet/go-ipfs/unixfs/io"
Matt Bell's avatar
Matt Bell committed
17
	u "github.com/jbenet/go-ipfs/util"
18
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
Matt Bell's avatar
Matt Bell committed
19 20
)

21 22
const nBitsForKeypairDefault = 4096

Matt Bell's avatar
Matt Bell committed
23
var initCmd = &cmds.Command{
24 25 26 27
	Helptext: cmds.HelpText{
		Tagline:          "Initializes IPFS config file",
		ShortDescription: "Initializes IPFS configuration files and generates a new keypair.",
	},
28

Matt Bell's avatar
Matt Bell committed
29
	Options: []cmds.Option{
30
		cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
31 32
		cmds.StringOption("passphrase", "p", "Passphrase for encrypting the private key"),
		cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
33 34 35 36 37

		// TODO need to decide whether to expose the override as a file or a
		// directory. That is: should we allow the user to also specify the
		// name of the file?
		// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
Matt Bell's avatar
Matt Bell committed
38
	},
39
	Run: func(req cmds.Request, res cmds.Response) {
40

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

47
		nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
48
		if err != nil {
49 50
			res.SetError(err, cmds.ErrNormal)
			return
51
		}
52
		if !bitsOptFound {
53
			nBitsForKeypair = nBitsForKeypairDefault
54 55
		}

56 57 58 59 60 61 62 63 64
		rpipe, wpipe := io.Pipe()
		go func() {
			defer wpipe.Close()
			if err := doInit(wpipe, req.Context().ConfigRoot, force, nBitsForKeypair); err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
		}()
		res.SetOutput(rpipe)
65 66
	},
}
Matt Bell's avatar
Matt Bell committed
67

68
var errRepoExists = debugerror.New(`ipfs configuration file already exists!
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69 70 71 72
Reinitializing would overwrite your keys.
(use -f to force overwrite)
`)

73 74
func initWithDefaults(out io.Writer, repoRoot string) error {
	err := doInit(out, repoRoot, false, nBitsForKeypairDefault)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
75
	return debugerror.Wrap(err)
76 77
}

78 79 80 81 82 83 84 85 86
func writef(out io.Writer, format string, ifs ...interface{}) error {
	_, err := out.Write([]byte(fmt.Sprintf(format, ifs...)))
	return err
}

func doInit(out io.Writer, repoRoot string, force bool, nBitsForKeypair int) error {
	if err := writef(out, "initializing ipfs node at %s\n", repoRoot); err != nil {
		return err
	}
87

88
	if fsrepo.IsInitialized(repoRoot) && !force {
89
		return errRepoExists
90
	}
91
	conf, err := config.Init(out, nBitsForKeypair)
92
	if err != nil {
93
		return err
94
	}
95
	if fsrepo.IsInitialized(repoRoot) {
96
		if err := fsrepo.Remove(repoRoot); err != nil {
97
			return err
98
		}
99
	}
100
	if err := fsrepo.Init(repoRoot, conf); err != nil {
101
		return err
102
	}
103

104 105
	if err := addDefaultAssets(out, repoRoot); err != nil {
		return err
Jeromy's avatar
Jeromy committed
106
	}
107 108

	return initializeIpnsKeyspace(repoRoot)
109 110
}

111
func addDefaultAssets(out io.Writer, repoRoot string) error {
112
	ctx, cancel := context.WithCancel(context.Background())
113 114 115 116 117 118
	defer cancel()
	r := fsrepo.At(repoRoot)
	if err := r.Open(); err != nil { // NB: repo is owned by the node
		return err
	}
	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
119
	if err != nil {
120
		return err
121 122 123
	}
	defer nd.Close()

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	dirb := uio.NewDirectory(nd.DAG)

	// add every file in the assets pkg
	for fname, file := range assets.Init_dir {
		buf := bytes.NewBufferString(file)
		s, err := coreunix.Add(nd, buf)
		if err != nil {
			return err
		}
		k := u.B58KeyDecode(s)
		if err := dirb.AddChild(fname, k); err != nil {
			return err
		}
	}

	dir := dirb.GetNode()
	dkey, err := nd.DAG.Add(dir)
141
	if err != nil {
142 143 144 145
		return err
	}
	if err := nd.Pinning.Pin(dir, true); err != nil {
		return err
146
	}
147 148 149 150 151 152
	if err := nd.Pinning.Flush(); err != nil {
		return err
	}

	writef(out, "to get started, enter:\n")
	return writef(out, "\n\tipfs cat /ipfs/%s/readme\n\n", dkey)
Matt Bell's avatar
Matt Bell committed
153
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
154

Jeromy's avatar
Jeromy committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
func initializeIpnsKeyspace(repoRoot string) error {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	r := fsrepo.At(repoRoot)
	if err := r.Open(); err != nil { // NB: repo is owned by the node
		return err
	}

	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
	if err != nil {
		return err
	}
	defer nd.Close()

	err = nd.SetupOfflineRouting()
	if err != nil {
		return err
	}

	return ipns.InitializeKeyspace(nd, nd.PrivateKey)
}