Add automatic RPC configuration.
This commit is contained in:
parent
6229e35835
commit
ff4ada0b0e
3 changed files with 180 additions and 0 deletions
|
@ -6,9 +6,11 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
|
@ -215,6 +217,13 @@ func loadConfig() (*config, []string, error) {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(preCfg.ConfigFile); os.IsNotExist(err) {
|
||||
err := createDefaultConfigFile(preCfg.ConfigFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error creating a default config file: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Load additional config from file.
|
||||
parser := flags.NewParser(&cfg, flags.Default)
|
||||
err = flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile)
|
||||
|
@ -268,3 +277,56 @@ func loadConfig() (*config, []string, error) {
|
|||
|
||||
return &cfg, remainingArgs, nil
|
||||
}
|
||||
|
||||
// createDefaultConfig creates a basic config file at the given destination path.
|
||||
// For this it tries to read the btcd config file at its default path, and extract
|
||||
// the RPC user and password from it.
|
||||
func createDefaultConfigFile(destinationPath string) error {
|
||||
// Create the destination directory if it does not exists
|
||||
os.MkdirAll(filepath.Dir(destinationPath), 0700)
|
||||
|
||||
// Read btcd.conf from its default path
|
||||
btcdConfigPath := filepath.Join(btcdHomeDir, "btcd.conf")
|
||||
btcdConfigFile, err := os.Open(btcdConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer btcdConfigFile.Close()
|
||||
content, err := ioutil.ReadAll(btcdConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Extract the rpcuser
|
||||
rpcUserRegexp, err := regexp.Compile(`(?m)^\s*rpcuser=([^\s]+)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userSubmatches := rpcUserRegexp.FindSubmatch(content)
|
||||
if userSubmatches == nil {
|
||||
// No user found, nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
// Extract the rpcpass
|
||||
rpcPassRegexp, err := regexp.Compile(`(?m)^\s*rpcpass=([^\s]+)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
passSubmatches := rpcPassRegexp.FindSubmatch(content)
|
||||
if passSubmatches == nil {
|
||||
// No password found, nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the destination file and write the rpcuser and rpcpass to it
|
||||
dest, err := os.OpenFile(destinationPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dest.Close()
|
||||
|
||||
dest.WriteString(fmt.Sprintf("rpcuser=%s\nrpcpass=%s", string(userSubmatches[1]), string(passSubmatches[1])))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
71
config.go
71
config.go
|
@ -5,8 +5,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -395,6 +399,13 @@ func loadConfig() (*config, []string, error) {
|
|||
if !(preCfg.RegressionTest || preCfg.SimNet) || preCfg.ConfigFile !=
|
||||
defaultConfigFile {
|
||||
|
||||
if _, err := os.Stat(preCfg.ConfigFile); os.IsNotExist(err) {
|
||||
err := createDefaultConfigFile(preCfg.ConfigFile)
|
||||
if err != nil {
|
||||
btcdLog.Warnf("Error creating a default config file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile)
|
||||
if err != nil {
|
||||
if _, ok := err.(*os.PathError); !ok {
|
||||
|
@ -880,6 +891,66 @@ func loadConfig() (*config, []string, error) {
|
|||
return &cfg, remainingArgs, nil
|
||||
}
|
||||
|
||||
// createDefaultConfig copies the file sample-btcd.conf to the given destination path,
|
||||
// and populates it with some randomly generated RPC username and password.
|
||||
func createDefaultConfigFile(destinationPath string) error {
|
||||
// Create the destination directory if it does not exists
|
||||
os.MkdirAll(filepath.Dir(destinationPath), 0700)
|
||||
|
||||
// We get the sample config file path, which is in the same directory as this file.
|
||||
_, path, _, _ := runtime.Caller(0)
|
||||
sampleConfigPath := filepath.Join(filepath.Dir(path), "sample-btcd.conf")
|
||||
|
||||
// We generate a random user and password
|
||||
randomBytes := make([]byte, 20)
|
||||
_, err := rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
generatedRPCUser := base64.StdEncoding.EncodeToString(randomBytes)
|
||||
|
||||
_, err = rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
generatedRPCPass := base64.StdEncoding.EncodeToString(randomBytes)
|
||||
|
||||
src, err := os.Open(sampleConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
dest, err := os.OpenFile(destinationPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dest.Close()
|
||||
|
||||
// We copy every line from the sample config file to the destination,
|
||||
// only replacing the two lines for rpcuser and rpcpass
|
||||
reader := bufio.NewReader(src)
|
||||
for err != io.EOF {
|
||||
var line string
|
||||
line, err = reader.ReadString('\n')
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
if strings.Contains(line, "rpcuser=") {
|
||||
line = "rpcuser=" + string(generatedRPCUser) + "\n"
|
||||
} else if strings.Contains(line, "rpcpass=") {
|
||||
line = "rpcpass=" + string(generatedRPCPass) + "\n"
|
||||
}
|
||||
|
||||
if _, err := dest.WriteString(line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// btcdDial connects to the address on the named network using the appropriate
|
||||
// dial function depending on the address and configuration options. For
|
||||
// example, .onion addresses will be dialed using the onion specific proxy if
|
||||
|
|
47
config_test.go
Normal file
47
config_test.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
rpcuserRegexp = regexp.MustCompile("(?m)^rpcuser=.+$")
|
||||
rpcpassRegexp = regexp.MustCompile("(?m)^rpcpass=.+$")
|
||||
)
|
||||
|
||||
func TestCreateDefaultConfigFile(t *testing.T) {
|
||||
// Setup a temporary directory
|
||||
tmpDir, err := ioutil.TempDir("", "btcd")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating a temporary directory: %v", err)
|
||||
}
|
||||
testpath := filepath.Join(tmpDir, "test.conf")
|
||||
// Clean-up
|
||||
defer func() {
|
||||
os.Remove(testpath)
|
||||
os.Remove(tmpDir)
|
||||
}()
|
||||
|
||||
err = createDefaultConfigFile(testpath)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a default config file: %v", err)
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(testpath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read generated default config file: %v", err)
|
||||
}
|
||||
|
||||
if !rpcuserRegexp.Match(content) {
|
||||
t.Error("Could not find rpcuser in generated default config file.")
|
||||
}
|
||||
|
||||
if !rpcpassRegexp.Match(content) {
|
||||
t.Error("Could not find rpcpass in generated default config file.")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue