Skip to content

Commit

Permalink
Refactor cli of tau (#125)
Browse files Browse the repository at this point in the history
- Export/Import Configuration
- Secure Export
- Geo Localization
  • Loading branch information
samyfodil committed Feb 9, 2024
1 parent aa6cea9 commit 9e31aaf
Show file tree
Hide file tree
Showing 11 changed files with 861 additions and 90 deletions.
8 changes: 8 additions & 0 deletions cli/app/app.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package app

import (
"github.com/taubyte/tau/config"
"github.com/urfave/cli/v2"
)

func newApp() *cli.App {
app := &cli.App{
Flags: []cli.Flag{
&cli.PathFlag{
Name: "root",
Value: config.DefaultRoot,
Usage: "Folder where tau is installed",
},
},
Commands: []*cli.Command{
startCommand(),
configCommand(),
Expand Down
51 changes: 28 additions & 23 deletions cli/app/config_cmd.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package app

import (
"github.com/pterm/pterm"
"github.com/taubyte/tau/config"
"github.com/urfave/cli/v2"
)

Expand All @@ -20,10 +18,6 @@ func configCommand() *cli.Command {
Name: "shape",
Aliases: []string{"s"},
},
&cli.PathFlag{
Name: "root",
DefaultText: config.DefaultRoot,
},
&cli.PathFlag{
Name: "path",
Aliases: []string{"p"},
Expand All @@ -42,10 +36,6 @@ func configCommand() *cli.Command {
Name: "shape",
Aliases: []string{"s"},
},
&cli.PathFlag{
Name: "root",
DefaultText: config.DefaultRoot,
},
&cli.PathFlag{
Name: "path",
Aliases: []string{"p"},
Expand All @@ -59,6 +49,25 @@ func configCommand() *cli.Command {
return displayConfig(pid, cnf)
},
},
{
Name: "export",
Usage: "export a configuration bundle",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "unsafe",
Usage: "export node private key (Only use to restore a node).",
},
&cli.StringFlag{
Name: "shape",
Aliases: []string{"s"},
},
&cli.BoolFlag{
Name: "protect",
Aliases: []string{"p"},
},
},
Action: exportConfig,
},
{
Name: "generate",
Aliases: []string{"gen"},
Expand All @@ -67,17 +76,14 @@ func configCommand() *cli.Command {
Name: "shape",
Aliases: []string{"s"},
},
&cli.PathFlag{
Name: "root",
Value: config.DefaultRoot,
},
&cli.StringFlag{
Name: "protocols",
Aliases: []string{"proto", "protos"},
Usage: "Protocols to enable. Use `all` to enable them all.",
},
&cli.StringFlag{
Name: "network",
Aliases: []string{"fqdn"},
Aliases: []string{"n", "fqdn"},
Value: "example.com",
},
&cli.IntFlag{
Expand All @@ -87,7 +93,8 @@ func configCommand() *cli.Command {
},
&cli.StringSliceFlag{
Name: "ip",
Aliases: []string{"address", "addr"},
Aliases: []string{"announce"},
Usage: "IP address to announce.",
},
&cli.StringSliceFlag{
Name: "bootstrap",
Expand All @@ -100,14 +107,12 @@ func configCommand() *cli.Command {
Name: "dv-keys",
Aliases: []string{"dv"},
},
&cli.PathFlag{
Name: "use",
Usage: "use a configuration template",
},
},
Action: func(ctx *cli.Context) error {
id, err := generateSourceConfig(ctx)
if id != "" {
pterm.Info.Println("ID:", id)
}
return err
},
Action: generateSourceConfig,
},
},
}
Expand Down
10 changes: 4 additions & 6 deletions cli/app/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (
)

func TestConfig(t *testing.T) {
app := newApp()

ctx, ctxC := context.WithTimeout(context.Background(), time.Second*15)
defer ctxC()

Expand All @@ -32,16 +30,16 @@ func TestConfig(t *testing.T) {
os.Mkdir(root+"/config", 0750)
os.Mkdir(root+"/config/keys", 0750)

err = app.RunContext(ctx, []string{os.Args[0], "cnf", "gen", "-s", "test", "--root", root, "--protos", "auth,seer,monkey", "--swarm-key", "--dv-keys"})
err = newApp().RunContext(ctx, []string{os.Args[0], "--root", root, "cnf", "gen", "-s", "test", "--protos", "auth,seer,monkey", "--swarm-key", "--dv-keys"})
assert.NilError(t, err)

err = app.RunContext(ctx, []string{os.Args[0], "cnf", "ok?", "-s", "test", "--root", root})
err = newApp().RunContext(ctx, []string{os.Args[0], "--root", root, "cnf", "ok?", "-s", "test"})
assert.NilError(t, err)

err = app.RunContext(ctx, []string{os.Args[0], "cnf", "show", "-s", "test", "--root", root})
err = newApp().RunContext(ctx, []string{os.Args[0], "--root", root, "cnf", "show", "-s", "test"})
assert.NilError(t, err)

config.DefaultRoot = root
err = app.RunContext(ctx, []string{os.Args[0], "cnf", "show", "-s", "test"})
err = newApp().RunContext(ctx, []string{os.Args[0], "cnf", "show", "-s", "test"})
assert.NilError(t, err)
}
137 changes: 137 additions & 0 deletions cli/app/export_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package app

import (
"encoding/base64"
"fmt"
"io"
"os"
"path"
"path/filepath"
"time"

"github.com/taubyte/tau/config"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v2"
)

func exportConfig(ctx *cli.Context) error {
root := ctx.Path("root")
if root == "" {
root = config.DefaultRoot
}

if !filepath.IsAbs(root) {
return fmt.Errorf("root folder `%s` is not absolute", root)
}

shape := ctx.String("shape")

configRoot := root + "/config"
configPath := ctx.Path("path")
if configPath == "" {
configPath = path.Join(configRoot, shape+".yaml")
}

data, err := os.ReadFile(configPath)
if err != nil {
return fmt.Errorf("shape %s does not exist", shape)
}

host, err := os.Hostname()
if err != nil {
return fmt.Errorf("faile to fetch hostname with %w", err)
}

var version *string
if v := ctx.String("version"); v != "" {
version = &v
}

bundle := &config.Bundle{
Origin: config.BundleOrigin{
Shape: shape,
Host: host,
Creation: time.Now(),
Version: version,
},
}

if err = yaml.Unmarshal(data, &(bundle.Source)); err != nil {
return fmt.Errorf("yaml unmarshal failed with: %w", err)
}

pkey := bundle.Privatekey
if !ctx.Bool("unsafe") {
pkey = ""
}

skfilename := path.Join(configRoot, bundle.Swarmkey)
skdata, err := os.ReadFile(skfilename)
if err != nil {
return fmt.Errorf("reading %s failed with: %w %#v", skfilename, err, bundle)
}

dvsfilename := path.Join(configRoot, bundle.Domains.Key.Private)
dvsdata, err := os.ReadFile(dvsfilename)
if err != nil {
return fmt.Errorf("reading %s failed with: %w", dvsfilename, err)
}

var dvpdata []byte
if bundle.Domains.Key.Public != "" {
dvpfilename := path.Join(configRoot, bundle.Domains.Key.Public)
dvpdata, err = os.ReadFile(dvpfilename)
if err != nil {
return fmt.Errorf("reading %s failed with: %w", dvsfilename, err)
}
}

if ctx.Bool("protect") {
bundle.Origin.Protected = true
if passwd, err := promptPassword("Password?"); err != nil {
return fmt.Errorf("faild to read password with %w", err)
} else {
if skdata, err = encrypt(skdata, passwd); err != nil {
return fmt.Errorf("faild to encrypt swarm key with %w", err)
}
if dvsdata, err = encrypt(dvsdata, passwd); err != nil {
return fmt.Errorf("faild to encrypt domain's private key key with %w", err)
}
if dvpdata != nil {
if dvpdata, err = encrypt(dvpdata, passwd); err != nil {
return fmt.Errorf("faild to encrypt domain's public key key with %w", err)
}
}
if pkey != "" {
pkdata, err := encrypt([]byte(pkey), passwd)
if err != nil {
return fmt.Errorf("faild to encrypt private key key with %w", err)
}
pkey = base64.StdEncoding.EncodeToString(pkdata)
}
}
}

bundle.Privatekey = pkey
bundle.Swarmkey = base64.StdEncoding.EncodeToString(skdata)
bundle.Domains.Key.Private = base64.StdEncoding.EncodeToString(dvsdata)
bundle.Domains.Key.Public = base64.StdEncoding.EncodeToString(dvpdata)

var out io.Writer = os.Stdout
if ctx.Args().Present() {
filename := ctx.Args().First()
f, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0460)
if err != nil {
return fmt.Errorf("fail to open %s with %w", filename, err)
}
defer f.Close()
out = f
}

err = yaml.NewEncoder(out).Encode(bundle)
if err != nil {
return fmt.Errorf("fail to marshal configuration with %w", err)
}

return nil
}
Loading

0 comments on commit 9e31aaf

Please sign in to comment.