Commit 96ca0646 authored by ElyKar's avatar ElyKar Committed by Loïck Bonniot

Integrate cobra and viper

parent 36c58689
......@@ -16,7 +16,7 @@ install_all: install
git stash
rm -rf gui
rm -rf dfssd/gui
rm -f dfssd/main.go
rm -f dfssd/cmd/gui.go
go install ./...
git reset --hard
......
......@@ -7,4 +7,6 @@ go get -u google.golang.org/grpc
go get -u github.com/pborman/uuid
go get -u github.com/stretchr/testify/assert
go get -u golang.org/x/crypto/ssh/terminal
go get -u github.com/spf13/viper
go get -u github.com/spf13/cobra
package main
import (
"fmt"
"os"
"dfss/dfssc/user"
)
func authUser(_ []string) {
fmt.Println("Authenticating user")
var mail, token string
readStringParam("Mail", "", &mail)
readStringParam("Token", "", &token)
err := user.Authenticate(fca, fcert, addrPort, mail, token)
if err != nil {
fmt.Println("An error occurred : ", err.Error())
os.Exit(3)
}
}
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"dfss/dfssc/user"
)
var authCmd = &cobra.Command{
Use: "auth",
Short: "authenticate a new client",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Authenticating user")
var mail, token string
readStringParam("Mail", "", &mail)
readStringParam("Token", "", &token)
err := user.Authenticate(mail, token)
if err != nil {
fmt.Println("An error occurred : ", err.Error())
os.Exit(3)
}
},
}
package cmd
import (
"fmt"
"os"
"path/filepath"
"github.com/spf13/cobra"
"dfss/dfssc/sign"
)
var fetchCmd = &cobra.Command{
Use: "fetch",
Short: "get a contract hosted on the platform",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Fetching a saved contract")
var passphrase, uuid, directory string
_ = readPassword(&passphrase, false)
readStringParam("Contract UUID", "", &uuid)
readStringParam("Save directory", ".", &directory)
path := filepath.Join(directory, uuid+".json")
err := sign.FetchContract(passphrase, uuid, path)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
},
}
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"dfss/dfssc/common"
"dfss/dfssc/user"
)
// export the certificate and private key of the user
var exportCmd = &cobra.Command{
Use: "export <c>",
Short: "export certificate and private key of the user to file c",
Run: func(cmd *cobra.Command, args []string) {
confFile := args[0]
fmt.Println("Export user configuration")
var keyPassphrase, confPassphrase string
config, err := user.NewConfig(common.SubViper("file_key", "file_cert"))
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldn't open the files: %s", err))
os.Exit(1)
return
}
err = readPassphrases(&keyPassphrase, &confPassphrase, true)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("An error occurred: %s", err))
os.Exit(1)
return
}
err = config.SaveConfigToFile(confFile, confPassphrase, keyPassphrase)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldn't save the configuration on the disk: %s", err))
os.Exit(1)
return
}
},
}
// import the configuration
var importCmd = &cobra.Command{
Use: "import <c>",
Short: "import private key and certificate of the user from file c",
Run: func(cmd *cobra.Command, args []string) {
confFile := args[0]
var keyPassphrase, confPassphrase string
err := readPassphrases(&keyPassphrase, &confPassphrase, false)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("An error occurred: %s", err))
os.Exit(1)
return
}
config, err := user.DecodeConfiguration(confFile, keyPassphrase, confPassphrase)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldnd't decrypt the configuration: %s", err))
os.Exit(1)
return
}
err = config.SaveUserInformations()
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldn't save the certificate and private key: %s", err))
os.Exit(1)
return
}
},
}
// Read two passphrases for the configuration
func readPassphrases(keyPassphrase, confPassphrase *string, second bool) error {
fmt.Println("Enter the passphrase of the configuration")
err := readPassword(confPassphrase, second)
if err != nil {
return err
}
fmt.Println("Enter the passphrase of your current key (if any)")
return readPassword(keyPassphrase, false)
}
package main
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"dfss/dfssc/sign"
)
func newContract(_ []string) {
fmt.Println("Creating a new contract")
passphrase, filepath, comment, signers := getContractInfo()
err := sign.SendNewContract(fca, fcert, fkey, addrPort, passphrase, filepath, comment, signers)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
var newCmd = &cobra.Command{
Use: "new",
Short: "create a new contract",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Creating a new contract")
passphrase, filepath, comment, signers := getContractInfo()
err := sign.SendNewContract(passphrase, filepath, comment, signers)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
},
}
// getContractInfo asks user for contract informations
......
package main
package cmd
import (
"bufio"
......@@ -10,40 +10,46 @@ import (
"strings"
"dfss/dfssc/user"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
)
func registerUser(_ []string) {
fmt.Println("Registering a new user")
// Initialize variables
var country, mail, organization, unit, passphrase string
var bits int
name := "Jon Doe"
u, err := osuser.Current()
if err == nil {
name = u.Name
}
var registerCmd = &cobra.Command{
Use: "register",
Short: "register a new client",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Registering a new user")
// Initialize variables
var country, mail, organization, unit, passphrase string
var bits int
name := "Jon Doe"
u, err := osuser.Current()
if err == nil {
name = u.Name
}
// Get all the necessary parameters
readStringParam("Mail", "", &mail)
readStringParam("Country", "FR", &country)
readStringParam("Organization", name, &organization)
readStringParam("Organizational unit", name, &unit)
readIntParam("Length of the key (2048 or 4096)", "2048", &bits)
err = readPassword(&passphrase, true)
if err != nil {
fmt.Println("An error occurred:", err.Error())
os.Exit(1)
return
}
// Get all the necessary parameters
readStringParam("Mail", "", &mail)
readStringParam("Country", "FR", &country)
readStringParam("Organization", name, &organization)
readStringParam("Organizational unit", name, &unit)
readIntParam("Length of the key (2048 or 4096)", "2048", &bits)
err = readPassword(&passphrase, true)
if err != nil {
fmt.Println("An error occurred:", err.Error())
os.Exit(1)
return
}
recapUser(mail, country, organization, unit)
err = user.Register(fca, fcert, fkey, addrPort, passphrase, country, organization, unit, mail, bits)
if err != nil {
fmt.Println("An error occurred:", err.Error())
os.Exit(2)
}
recapUser(mail, country, organization, unit)
err = user.Register(passphrase, country, organization, unit, mail, bits)
if err != nil {
fmt.Fprintln(os.Stderr, "An error occurred:", err.Error())
os.Exit(2)
}
},
}
// We need to use ONLY ONE reader: buffio buffers some data (= consumes from stdin)
......
package cmd
import (
"dfss"
dapi "dfss/dfssd/api"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// RootCmd is the main command for the dfssc application
var RootCmd = &cobra.Command{
Use: "dfssc",
Short: "DFSS command-line client",
Long: `Command-line client v` + dfss.Version + ` for the
Distributed Fair Signing System project
A tool to sign multiparty contract using a secure cryptographic protocol`,
Run: func(cmd *cobra.Command, args []string) {
_ = cmd.Help()
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
dapi.Configure(viper.GetString("demo") != "", viper.GetString("demo"), "client")
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
dapi.DClose()
},
}
// All of the flags will be gathered by viper, this is why
// we do not store their values
func init() {
// Bind flags to the dfsst command
RootCmd.PersistentFlags().BoolP("verbose", "v", false, "print verbose messages")
RootCmd.PersistentFlags().String("ca", "ca.pem", "path to the root certificate")
RootCmd.PersistentFlags().String("cert", "cert.pem", "path to the user's certificate")
RootCmd.PersistentFlags().String("key", "key.pem", "path to the user's private key")
RootCmd.PersistentFlags().StringP("demo", "d", "", "demonstrator address and port, empty will disable it")
RootCmd.PersistentFlags().String("host", "localhost:9000", "host of the dfss platform")
RootCmd.PersistentFlags().IntP("port", "p", 9005, "port to use for P2P communication between clients")
// Store flag values into viper
_ = viper.BindPFlag("verbose", RootCmd.PersistentFlags().Lookup("verbose"))
_ = viper.BindPFlag("file_ca", RootCmd.PersistentFlags().Lookup("ca"))
_ = viper.BindPFlag("file_cert", RootCmd.PersistentFlags().Lookup("cert"))
_ = viper.BindPFlag("file_key", RootCmd.PersistentFlags().Lookup("key"))
_ = viper.BindPFlag("demo", RootCmd.PersistentFlags().Lookup("demo"))
_ = viper.BindPFlag("local_port", RootCmd.PersistentFlags().Lookup("port"))
_ = viper.BindPFlag("platform_addrport", RootCmd.PersistentFlags().Lookup("host"))
// Bind subcommands to root
RootCmd.AddCommand(versionCmd, registerCmd, authCmd, newCmd, showCmd, fetchCmd, importCmd, exportCmd, signCmd)
}
package main
package cmd
import (
"bytes"
......@@ -8,6 +8,8 @@ import (
"dfss/dfssc/common"
"dfss/dfssp/contract"
"github.com/spf13/cobra"
)
const contractShowTemplate = `UUID : {{.UUID}}
......@@ -22,22 +24,13 @@ Signers :
{{range .Signers}} - {{.Email}}
{{end}}`
func getContract(filename string) *contract.JSON {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println("Cannot open file:", err)
return nil
}
c, err := common.UnmarshalDFSSFile(data)
if err != nil {
fmt.Println("Corrupted file:", err)
return nil
}
return c
var showCmd = &cobra.Command{
Use: "show <c>",
Short: "print contract information from file c",
Run: showContract,
}
func showContract(args []string) {
func showContract(cmd *cobra.Command, args []string) {
filename := args[0]
c := getContract(filename)
if c == nil {
......@@ -57,3 +50,18 @@ func showContract(args []string) {
}
fmt.Print(b.String())
}
func getContract(filename string) *contract.JSON {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println("Cannot open file:", err)
return nil
}
c, err := common.UnmarshalDFSSFile(data)
if err != nil {
fmt.Println("Corrupted file:", err)
return nil
}
return c
}
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"dfss/dfssc/sign"
)
var signCmd = &cobra.Command{
Use: "sign <c>",
Short: "sign contract from file c",
Run: func(cmd *cobra.Command, args []string) {
filename := args[0]
fmt.Println("You are going to sign the following contract:")
showContract(cmd, args)
contract := getContract(filename)
if contract == nil {
os.Exit(1)
}
var passphrase string
_ = readPassword(&passphrase, false)
// Preparation
manager, err := sign.NewSignatureManager(passphrase, contract)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
manager.OnSignerStatusUpdate = signFeedbackFn
err = manager.ConnectToPeers()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(3)
}
// Confirmation
var ready string
readStringParam("Do you REALLY want to sign "+contract.File.Name+"? Type 'yes' to confirm", "", &ready)
if ready != "yes" {
os.Exit(4)
}
// Ignition
fmt.Println("Waiting for other signers to be ready...")
signatureUUID, err := manager.SendReadySign()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(5)
}
// TODO Warning, integration tests are checking Stdout
fmt.Println("Everybody is ready, starting the signature", signatureUUID)
// Signature
manager.OnProgressUpdate = signProgressFn
err = manager.Sign()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(5)
}
// Persist evidencies, if any
err = manager.PersistSignaturesToFile()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(5)
}
fmt.Println("Signature complete! See .proof file for evidences.")
},
}
func signFeedbackFn(mail string, status sign.SignerStatus, data string) {
if status == sign.StatusConnecting {
fmt.Println("- Trying to connect with", mail, "/", data)
} else if status == sign.StatusConnected {
fmt.Println(" Successfully connected!", "[", data, "]")
}
}
func signProgressFn(current int, max int) {}
package cmd
import (
"dfss"
"fmt"
"runtime"
"github.com/spf13/cobra"
)
// versionCmd represents the version command
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print dfss protocol version",
Long: "Print dfss protocol version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH)
},
}
package common
import (
"github.com/spf13/viper"
)
// SubViper : From the singleton viper, creates another config
// object which holds only a part of of the config
func SubViper(args ...string) *viper.Viper {
v := viper.New()
for _, arg := range args {
v.Set(arg, viper.Get(arg))
}
return v
}
// MockViper : Creates a dummy viper object to use
// in tests instead of the real one, the expected args
// are key1, val1, key2, val2, etc...
func MockViper(args ...interface{}) *viper.Viper {
v := viper.New()
key := ""
isValue := false
for _, arg := range args {
if isValue {
v.Set(key, arg)
} else {
key = arg.(string)
}
isValue = !isValue
}
return v
}
package main
import (
"fmt"
"os"
"path/filepath"
"dfss/dfssc/sign"
)
func fetchContract(_ []string) {
fmt.Println("Fetching a saved contract")
var passphrase, uuid, directory string
_ = readPassword(&passphrase, false)
readStringParam("Contract UUID", "", &uuid)
readStringParam("Save directory", ".", &directory)
path := filepath.Join(directory, uuid+".json")
err := sign.FetchContract(fca, fcert, fkey, addrPort, passphrase, uuid, path)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
package main
import (
"dfss/dfssc/user"
"fmt"
"os"
)
// export the certificate and private key of the user
func exportConf(args []string) {
confFile := args[0]
fmt.Println("Export user configuration")
var keyPassphrase, confPassphrase string
config, err := user.NewConfig(fkey, fcert)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldn't open the files: %s", err))
os.Exit(1)
return
}
err = readPassphrases(&keyPassphrase, &confPassphrase, true)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("An error occurred: %s", err))
os.Exit(1)
return
}
err = config.SaveConfigToFile(confFile, confPassphrase, keyPassphrase)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldn't save the configuration on the disk: %s", err))
os.Exit(1)
return
}
}
// Read two passphrases for the configuration
func readPassphrases(keyPassphrase, confPassphrase *string, second bool) error {
fmt.Println("Enter the passphrase of the configuration")
err := readPassword(confPassphrase, second)
if err != nil {
return err
}
fmt.Println("Enter the passphrase of your current key (if any)")
return readPassword(keyPassphrase, false)
}
// import the configuration
func importConf(args []string) {
confFile := args[0]
var keyPassphrase, confPassphrase string
err := readPassphrases(&keyPassphrase, &confPassphrase, false)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("An error occurred: %s", err))
os.Exit(1)
return
}
config, err := user.DecodeConfiguration(confFile, keyPassphrase, confPassphrase)
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldnd't decrypt the configuration: %s", err))
os.Exit(1)
return
}
err = config.SaveUserInformations()
if err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("Couldn't save the certificate and private key: %s", err))
os.Exit(1)
return
}
}
package main
import (
"dfss"
"flag"
"fmt"
"runtime"
"os"
dapi "dfss/dfssd/api"
"dfss/dfssc/cmd"
)
var (
verbose bool
demo string
fca string // Path to the CA
fcert string // Path to the certificate
fkey string // Path to the private key
addrPort string // Address and port of the platform
localPort int // Port to open for P2P communication
)
func init() {
flag.BoolVar(&verbose, "v", false, "Print verbose messages")
flag.StringVar(&fca, "ca", "ca.pem", "Path to the root certificate")
flag.StringVar(&fcert, "cert", "cert.pem", "Path to the user certificate")
flag.StringVar(&fkey, "key", "key.pem", "Path to the private key")
flag.StringVar(&addrPort, "host", "localhost:9000", "Host of the DFSS platform")
flag.StringVar(&demo, "d", "", "Demonstrator address and port (empty string disables debug)")
flag.IntVar(&localPort, "port", 9005, "Port to use for P2P communication between clients")
flag.Usage = func() {
fmt.Println("DFSS client command line v" + dfss.Version)
fmt.Println("A tool to sign multiparty contracts")
fmt.Println("\nUsage:")
fmt.Println(" dfssc [flags] command")
fmt.Println("\nThe commands are:")
fmt.Println(" help print this help")
fmt.Println(" version print dfss client version")
fmt.Println(" register register a new client")
fmt.Println(" auth authenticate a new client")
fmt.Println(" new create a new contract")
fmt.Println(" fetch get a contract hosted on the platform")
fmt.Println(" show <c> print contract information from file c")