Newer
Older
wg-portal / cmd / cli / main.go
@Christoph Haas Christoph Haas on 17 Jan 2022 4 KB restructure
package main

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/h44z/wg-portal/internal/core"
	"github.com/h44z/wg-portal/internal/persistence"

	"github.com/pkg/errors"

	"github.com/urfave/cli/v2"
)

const (
	dsnFlag       = "dsn"
	interfaceFlag = "interface"
)

var backend core.Backend

var globalFlags = []cli.Flag{
	&cli.StringFlag{
		Name:  dsnFlag,
		Value: "./sqlite.db",
		Usage: "A DSN for the data store.",
	},
}

var commands = []*cli.Command{
	{
		Name:    "list",
		Aliases: []string{"l"},
		Usage:   "list interfaces or peers",
		Subcommands: []*cli.Command{
			{
				Name:      "interface",
				Usage:     "show interface information",
				ArgsUsage: "<interface identifier>",
				Action: func(c *cli.Context) error {
					if c.Args().Len() != 1 {
						return errors.New("missing/invalid interface identifier")
					}
					interfaceIdentifier := persistence.InterfaceIdentifier(strings.TrimSpace(c.Args().Get(0)))

					cfg, err := backend.GetInterface(interfaceIdentifier)
					if err != nil {
						return errors.WithMessage(err, "failed to get interface")
					}

					peers, err := backend.GetPeers(interfaceIdentifier)
					if err != nil {
						return errors.WithMessage(err, "failed to get interface peers")
					}

					config, err := backend.GetInterfaceConfig(cfg, peers)
					if err != nil {
						return errors.WithMessage(err, "failed to get interface config")
					}

					fmt.Println(config)

					return nil
				},
			},
			{
				Name:  "interfaces",
				Usage: "list all interfaces",
				Action: func(c *cli.Context) error {
					interfaces, err := backend.GetInterfaces()
					if err != nil {
						return errors.WithMessage(err, "failed to get all interfaces")
					}

					fmt.Println("Managed WireGuard Interfaces:")
					for i, cfg := range interfaces {
						desc := ""
						if cfg.DisplayName != "" {
							desc = fmt.Sprintf(" (%s)", cfg.DisplayName)
						}
						fmt.Printf(" %d\t%s%s\n", i, cfg.Identifier, desc)
					}

					importable, err := backend.GetImportableInterfaces()
					if err != nil {
						return errors.WithMessage(err, "failed to get importable interfaces")
					}

					fmt.Println("Importable WireGuard Interfaces:")
					i := 0
					for cfg := range importable {
						fmt.Printf(" %d\t%s\n", i, cfg.Identifier)
						i++
					}

					return nil
				},
			},
			{
				Name:      "peers",
				Usage:     "list all peers",
				ArgsUsage: "<interface identifier>",
				Action: func(c *cli.Context) error {
					if c.Args().Len() != 1 {
						return errors.New("missing/invalid interface identifier")
					}
					interfaceIdentifier := persistence.InterfaceIdentifier(strings.TrimSpace(c.Args().Get(0)))

					peers, err := backend.GetPeers(interfaceIdentifier)
					if err != nil {
						return errors.WithMessage(err, "failed to get all peers")
					}

					fmt.Println("WireGuard Peers:")
					for i, cfg := range peers {
						desc := ""
						if cfg.DisplayName != "" {
							desc = fmt.Sprintf(" (%s)", cfg.DisplayName)
						}
						fmt.Printf(" %d\t%s%s\n", i, cfg.Identifier, desc)
					}
					return nil
				},
			},
		},
	},
	{
		Name:      "import",
		Aliases:   []string{"i"},
		Usage:     "import existing interface",
		ArgsUsage: "<interface identifier>",
		Action: func(c *cli.Context) error {
			if c.Args().Len() != 1 {
				return errors.New("missing/invalid interface identifier")
			}
			importIdentifier := strings.TrimSpace(c.Args().Get(0))

			err := backend.ImportInterfaceById(persistence.InterfaceIdentifier(importIdentifier))
			if err != nil {
				return err
			}

			fmt.Println("Imported interface", importIdentifier)

			return nil
		},
	},
}

func main() {
	app := cli.NewApp()
	app.Name = "wg-portal"
	app.Version = "0.0.1"
	app.Usage = "WireGuard Portal CLI client"
	app.EnableBashCompletion = true
	app.Commands = commands
	app.Flags = globalFlags
	app.Before = func(c *cli.Context) error {
		dsn := c.String(dsnFlag)
		database, err := persistence.NewDatabase(persistence.DatabaseConfig{
			Type: "sqlite",
			DSN:  dsn,
		})
		if err != nil {
			return errors.WithMessagef(err, "failed to initialize persistent store")
		}

		backend, err = core.NewPersistentBackend(database)
		if err != nil {
			return errors.WithMessagef(err, "backend failed to initialize")
		}
		return nil
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}