1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-08-06 19:44:01 +08:00
Files
kubo/cmd/ipfs/init.go
Steven Allen 2eafa3f3ca startup: always load the private key
Loading this at the last minute means we need a bunch of special cases
in *every* command that needs routing, namesys, or even the public key.

If we ever have a case where we don't want to do this, we can add an option to
the (eventual) IPFS constructor. Handling this up-front is going to be
significantly less error prone.

Motivation: https://github.com/ipfs/go-ipfs/pull/5825/files#diff-fe35ea64d478c4f3fb767a3f618e5d01R863

License: MIT
Signed-off-by: Steven Allen <steven@stebalien.com>
2018-12-13 11:48:55 -08:00

242 lines
6.1 KiB
Go

package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path"
"strings"
assets "github.com/ipfs/go-ipfs/assets"
oldcmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
namesys "github.com/ipfs/go-ipfs/namesys"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
"gx/ipfs/QmYyzmMnhNTtoXx5ttgUaRdHHckYnQWjPL98hgLAR2QLDD/go-ipfs-config"
"gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)
const (
nBitsForKeypairDefault = 2048
)
var initCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Initializes ipfs config file.",
ShortDescription: `
Initializes ipfs configuration files and generates a new keypair.
If you are going to run IPFS in server environment, you may want to
initialize it using 'server' profile.
For the list of available profiles see 'ipfs config profile --help'
ipfs uses a repository in the local file system. By default, the repo is
located at ~/.ipfs. To change the repo location, set the $IPFS_PATH
environment variable:
export IPFS_PATH=/path/to/ipfsrepo
`,
},
Arguments: []cmdkit.Argument{
cmdkit.FileArg("default-config", false, false, "Initialize with the given configuration.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.IntOption("bits", "b", "Number of bits to use in the generated RSA private key.").WithDefault(nBitsForKeypairDefault),
cmdkit.BoolOption("empty-repo", "e", "Don't add and pin help files to the local storage."),
cmdkit.StringOption("profile", "p", "Apply profile settings to config. Multiple profiles can be separated by ','"),
// 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 cmdkit.StringOption("event-logs", "l", "Location for machine-readable event logs."),
},
PreRun: func(req *cmds.Request, env cmds.Environment) error {
cctx := env.(*oldcmds.Context)
daemonLocked, err := fsrepo.LockedByOtherProcess(cctx.ConfigRoot)
if err != nil {
return err
}
log.Info("checking if daemon is running...")
if daemonLocked {
log.Debug("ipfs daemon is running")
e := "ipfs daemon is running. please stop it to run this command"
return cmds.ClientError(e)
}
return nil
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
cctx := env.(*oldcmds.Context)
if cctx.Online {
return cmdkit.Error{Message: "init must be run offline only"}
}
empty, _ := req.Options["empty-repo"].(bool)
nBitsForKeypair, _ := req.Options["bits"].(int)
var conf *config.Config
f := req.Files
if f != nil {
confFile, err := f.NextFile()
if err != nil {
return err
}
conf = &config.Config{}
if err := json.NewDecoder(confFile).Decode(conf); err != nil {
return err
}
}
profile, _ := req.Options["profile"].(string)
var profiles []string
if profile != "" {
profiles = strings.Split(profile, ",")
}
return doInit(os.Stdout, cctx.ConfigRoot, empty, nBitsForKeypair, profiles, conf)
},
}
var errRepoExists = errors.New(`ipfs configuration file already exists!
Reinitializing would overwrite your keys.
`)
func initWithDefaults(out io.Writer, repoRoot string, profile string) error {
var profiles []string
if profile != "" {
profiles = strings.Split(profile, ",")
}
return doInit(out, repoRoot, false, nBitsForKeypairDefault, profiles, nil)
}
func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, confProfiles []string, conf *config.Config) error {
if _, err := fmt.Fprintf(out, "initializing IPFS node at %s\n", repoRoot); err != nil {
return err
}
if err := checkWritable(repoRoot); err != nil {
return err
}
if fsrepo.IsInitialized(repoRoot) {
return errRepoExists
}
if conf == nil {
var err error
conf, err = config.Init(out, nBitsForKeypair)
if err != nil {
return err
}
}
for _, profile := range confProfiles {
transformer, ok := config.Profiles[profile]
if !ok {
return fmt.Errorf("invalid configuration profile: %s", profile)
}
if err := transformer.Transform(conf); err != nil {
return err
}
}
if err := fsrepo.Init(repoRoot, conf); err != nil {
return err
}
if !empty {
if err := addDefaultAssets(out, repoRoot); err != nil {
return err
}
}
return initializeIpnsKeyspace(repoRoot)
}
func checkWritable(dir string) error {
_, err := os.Stat(dir)
if err == nil {
// dir exists, make sure we can write to it
testfile := path.Join(dir, "test")
fi, err := os.Create(testfile)
if err != nil {
if os.IsPermission(err) {
return fmt.Errorf("%s is not writeable by the current user", dir)
}
return fmt.Errorf("unexpected error while checking writeablility of repo root: %s", err)
}
fi.Close()
return os.Remove(testfile)
}
if os.IsNotExist(err) {
// dir doesn't exist, check that we can create it
return os.Mkdir(dir, 0775)
}
if os.IsPermission(err) {
return fmt.Errorf("cannot write to %s, incorrect permissions", err)
}
return err
}
func addDefaultAssets(out io.Writer, repoRoot string) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
r, err := fsrepo.Open(repoRoot)
if err != nil { // NB: repo is owned by the node
return err
}
nd, err := core.NewNode(ctx, &core.BuildCfg{Repo: r})
if err != nil {
return err
}
defer nd.Close()
dkey, err := assets.SeedInitDocs(nd)
if err != nil {
return fmt.Errorf("init: seeding init docs failed: %s", err)
}
log.Debugf("init: seeded init docs %s", dkey)
if _, err = fmt.Fprintf(out, "to get started, enter:\n"); err != nil {
return err
}
_, err = fmt.Fprintf(out, "\n\tipfs cat /ipfs/%s/readme\n\n", dkey)
return err
}
func initializeIpnsKeyspace(repoRoot string) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
r, err := fsrepo.Open(repoRoot)
if err != nil { // NB: repo is owned by the node
return err
}
nd, err := core.NewNode(ctx, &core.BuildCfg{Repo: r})
if err != nil {
return err
}
defer nd.Close()
return namesys.InitializeKeyspace(ctx, nd.Namesys, nd.Pinning, nd.PrivateKey)
}