Skip to content

Commit

Permalink
Merge pull request #4 from guggero/newline-trim-fix
Browse files Browse the repository at this point in the history
Newline trim fix
  • Loading branch information
guggero authored Mar 22, 2022
2 parents 70784c8 + fd7a6d3 commit 31c4dc4
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 95 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ env:
GOCACHE: /home/runner/work/go/pkg/build
GOPATH: /home/runner/work/go

GO_VERSION: 1.17.6

jobs:
########################
# lint code
Expand All @@ -32,3 +34,32 @@ jobs:

- name: lint
run: make lint

########################
# run unit tests
########################
unit-test:
name: run unit tests
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v2

- name: go cache
uses: actions/cache@v1
with:
path: /home/runner/work/go
key: lnd-${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ github.job }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
lndinit-${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ github.job }}-${{ hashFiles('**/go.sum') }}
lndinit-${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ github.job }}-
lndinit-${{ runner.os }}-go-${{ env.GO_VERSION }}-
lndinit-${{ runner.os }}-go-
- name: setup go ${{ env.GO_VERSION }}
uses: actions/setup-go@v2
with:
go-version: '${{ env.GO_VERSION }}'

- name: run unit test
run: make unit
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ COMMIT_HASH := $(shell git rev-parse HEAD)

GOBUILD := go build -v
GOINSTALL := go install -v
GOTEST := go test
GOTEST := go test -v
DOCKER_TOOLS := docker run -v $$(pwd):/build lndinit-tools

GOFILES_NOVENDOR = $(shell find . -type f -name '*.go' -not -path "./vendor/*")
Expand Down Expand Up @@ -103,6 +103,10 @@ scratch: build
# UTILITIES
# =========

unit:
@$(call print, "Running unit tests.")
$(GOTEST) ./...

fmt: $(GOIMPORTS_BIN)
@$(call print, "Fixing imports.")
gosimports -w $(GOFILES_NOVENDOR)
Expand Down
2 changes: 1 addition & 1 deletion cmd_gen_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (x *genPasswordCommand) Execute(_ []string) error {
}
}

fmt.Printf("%s\n", passwordString)
fmt.Printf("%s", passwordString)

return nil
}
2 changes: 1 addition & 1 deletion cmd_gen_seed.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (x *genSeedCommand) Execute(_ []string) error {
}
}

fmt.Printf("%s\n", seedWords)
fmt.Printf("%s", seedWords)

return nil
}
158 changes: 88 additions & 70 deletions cmd_init_wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,76 +107,9 @@ func (x *initWalletCommand) Execute(_ []string) error {
requireSeed := (x.InitType == typeFile) ||
(x.InitType == typeRpc && !x.InitRpc.WatchOnly)

// First find out where we want to read the secrets from.
var (
seed string
seedPassPhrase string
walletPassword string
err error
)
switch x.SecretSource {
// Read all secrets from individual files.
case storageFile:
if requireSeed {
log("Reading seed from file")
seed, err = readFile(x.File.Seed)
if err != nil {
return err
}
}

// The seed passphrase is optional.
if x.File.SeedPassphrase != "" {
log("Reading seed passphrase from file")
seedPassPhrase, err = readFile(x.File.SeedPassphrase)
if err != nil {
return err
}
}

log("Reading wallet password from file")
walletPassword, err = readFile(x.File.WalletPassword)
if err != nil {
return err
}

// Read passphrase from Kubernetes secret.
case storageK8s:
k8sSecret := &k8sSecretOptions{
Namespace: x.K8s.Namespace,
SecretName: x.K8s.SecretName,
Base64: x.K8s.Base64,
}
k8sSecret.SecretKeyName = x.K8s.SeedKeyName

if requireSeed {
log("Reading seed from k8s secret %s (namespace %s)",
x.K8s.SecretName, x.K8s.Namespace)
seed, _, err = readK8s(k8sSecret)
if err != nil {
return err
}
}

// The seed passphrase is optional.
if x.K8s.SeedPassphraseKeyName != "" {
log("Reading seed passphrase from k8s secret %s "+
"(namespace %s)", x.K8s.SecretName,
x.K8s.Namespace)
k8sSecret.SecretKeyName = x.K8s.SeedPassphraseKeyName
seedPassPhrase, _, err = readK8s(k8sSecret)
if err != nil {
return err
}
}

log("Reading wallet password from k8s secret %s (namespace %s)",
x.K8s.SecretName, x.K8s.Namespace)
k8sSecret.SecretKeyName = x.K8s.WalletPasswordKeyName
walletPassword, _, err = readK8s(k8sSecret)
if err != nil {
return err
}
seed, seedPassPhrase, walletPassword, err := x.readInput(requireSeed)
if err != nil {
return fmt.Errorf("error reading input parameters: %v", err)
}

switch x.InitType {
Expand Down Expand Up @@ -268,6 +201,91 @@ func (x *initWalletCommand) Execute(_ []string) error {
}
}

func (x *initWalletCommand) readInput(requireSeed bool) (string, string, string,
error) {

// First find out where we want to read the secrets from.
var (
seed string
seedPassPhrase string
walletPassword string
err error
)
switch x.SecretSource {
// Read all secrets from individual files.
case storageFile:
if requireSeed {
log("Reading seed from file")
seed, err = readFile(x.File.Seed)
if err != nil {
return "", "", "", err
}
}

// The seed passphrase is optional.
if x.File.SeedPassphrase != "" {
log("Reading seed passphrase from file")
seedPassPhrase, err = readFile(x.File.SeedPassphrase)
if err != nil {
return "", "", "", err
}
}

log("Reading wallet password from file")
walletPassword, err = readFile(x.File.WalletPassword)
if err != nil {
return "", "", "", err
}

// Read passphrase from Kubernetes secret.
case storageK8s:
k8sSecret := &k8sSecretOptions{
Namespace: x.K8s.Namespace,
SecretName: x.K8s.SecretName,
Base64: x.K8s.Base64,
}
k8sSecret.SecretKeyName = x.K8s.SeedKeyName

if requireSeed {
log("Reading seed from k8s secret %s (namespace %s)",
x.K8s.SecretName, x.K8s.Namespace)
seed, _, err = readK8s(k8sSecret)
if err != nil {
return "", "", "", err
}
}

// The seed passphrase is optional.
if x.K8s.SeedPassphraseKeyName != "" {
log("Reading seed passphrase from k8s secret %s "+
"(namespace %s)", x.K8s.SecretName,
x.K8s.Namespace)
k8sSecret.SecretKeyName = x.K8s.SeedPassphraseKeyName
seedPassPhrase, _, err = readK8s(k8sSecret)
if err != nil {
return "", "", "", err
}
}

log("Reading wallet password from k8s secret %s (namespace %s)",
x.K8s.SecretName, x.K8s.Namespace)
k8sSecret.SecretKeyName = x.K8s.WalletPasswordKeyName
walletPassword, _, err = readK8s(k8sSecret)
if err != nil {
return "", "", "", err
}
}

// The seed, its passphrase and the wallet password should all never
// have a newline at their end, otherwise that might lead to errors
// further down the line.
seed = stripNewline(seed)
seedPassPhrase = stripNewline(seedPassPhrase)
walletPassword = stripNewline(walletPassword)

return seed, seedPassPhrase, walletPassword, nil
}

func createWalletFile(cipherSeed *aezeed.CipherSeed, walletPassword, walletDir,
network string, validatePassword bool) error {

Expand Down
38 changes: 38 additions & 0 deletions cmd_init_wallet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"io/ioutil"
"testing"

"github.com/stretchr/testify/require"
)

var (
testSeedWithNewline = []byte("seed phrase with newline\n")
testPasswordWithNewline = []byte("p4ssw0rd\r\n\n\r\r\n")
)

// TestReadInput makes sure input files are always trimmed so we don't have any
// newline characters left over.
func TestReadInput(t *testing.T) {
cmd := newInitWalletCommand()

cmd.File.Seed = writeToTempFile(t, testSeedWithNewline)
cmd.File.WalletPassword = writeToTempFile(t, testPasswordWithNewline)

seed, seedPassphrase, walletPassword, err := cmd.readInput(true)
require.NoError(t, err)
require.Equal(t, "seed phrase with newline", seed)
require.Equal(t, "", seedPassphrase)
require.Equal(t, "p4ssw0rd", walletPassword)
}

func writeToTempFile(t *testing.T, data []byte) string {
tempFileName, err := ioutil.TempFile("", "*.txt")
require.NoError(t, err)

err = ioutil.WriteFile(tempFileName.Name(), data, 0600)
require.NoError(t, err)

return tempFileName.Name()
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/kkdai/bstream v1.0.0
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display
github.com/lightningnetwork/lnd v0.14.2-beta
github.com/stretchr/testify v1.7.0
google.golang.org/grpc v1.38.0
k8s.io/api v0.18.3
k8s.io/apimachinery v0.18.3
Expand Down Expand Up @@ -92,7 +93,6 @@ require (
github.com/sirupsen/logrus v1.7.0 // indirect
github.com/soheilhy/cmux v0.1.5 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
Expand Down
37 changes: 23 additions & 14 deletions k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,22 +93,14 @@ func readK8s(opts *k8sSecretOptions) (string, *jsonK8sObject, error) {
opts.SecretKeyName)
}

// Remove any newlines at the end of the file. We won't ever write a
// newline ourselves but maybe the file was provisioned by another
// process or user.
content := stripNewline(string(secret.Data[opts.SecretKeyName]))

// There is an additional layer of base64 encoding applied to each of
// the secrets. Try to de-code it now.
if opts.Base64 {
decoded, err := base64.StdEncoding.DecodeString(content)
if err != nil {
return "", nil, fmt.Errorf("failed to base64 decode "+
"secret %s key %s: %v", opts.SecretName,
opts.SecretKeyName, err)
}

content = stripNewline(string(decoded))
content, err := secretToString(
secret.Data[opts.SecretKeyName], opts.Base64,
)
if err != nil {
return "", nil, fmt.Errorf("failed to decode raw secret %s "+
"key %s: %v", opts.SecretName, opts.SecretKeyName, err)
}

return content, &jsonK8sObject{
Expand Down Expand Up @@ -243,3 +235,20 @@ func createSecretK8s(client *kubernetes.Clientset, opts *k8sSecretOptions,

return nil
}

// secretToString turns the raw bytes of a secret into a string, removing the
// additional layer of base64 encoding if there is expected to be one.
func secretToString(rawSecret []byte, doubleBase64 bool) (string, error) {
content := string(rawSecret)
if doubleBase64 {
decoded, err := base64.StdEncoding.DecodeString(content)
if err != nil {
return "", fmt.Errorf("failed to base64 decode: %v",
err)
}

content = string(decoded)
}

return content, nil
}
Loading

0 comments on commit 31c4dc4

Please sign in to comment.