diff --git a/Makefile b/Makefile index 932bb133aa017d510ece0687fbb00e9213734ae1..58c78782489c1d334bf8555b79441c5ac116bc3c 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,9 @@ install: nocache install_all: install git stash rm -rf gui + rm -rf dfssd/cmd rm -rf dfssd/gui - rm -f dfssd/main.go + rm dfssd/main.go go install ./... git reset --hard diff --git a/build/deps.sh b/build/deps.sh index 1e31520857b6eedf1bb938f4a756e61d1f629508..6e78a3cd1374df51c6170393b68fd3be03064350 100755 --- a/build/deps.sh +++ b/build/deps.sh @@ -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 diff --git a/dfssc/authenticate.go b/dfssc/authenticate.go deleted file mode 100644 index 5b8926576795428f6c9affb93a147087036b4ae3..0000000000000000000000000000000000000000 --- a/dfssc/authenticate.go +++ /dev/null @@ -1,22 +0,0 @@ -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) - } -} diff --git a/dfssc/cmd/authenticate.go b/dfssc/cmd/authenticate.go new file mode 100644 index 0000000000000000000000000000000000000000..33a58252bf434c17a16c5a7ae8f431725a297a1d --- /dev/null +++ b/dfssc/cmd/authenticate.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "fmt" + "os" + + "dfss/dfssc/user" + "github.com/spf13/cobra" +) + +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(1) + } + }, +} diff --git a/dfssc/cmd/fetch.go b/dfssc/cmd/fetch.go new file mode 100644 index 0000000000000000000000000000000000000000..af9e3760b112f8c7f228be9e71565db802448707 --- /dev/null +++ b/dfssc/cmd/fetch.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "fmt" + "os" + "path/filepath" + + "dfss/dfssc/sign" + "github.com/spf13/cobra" +) + +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) + } + }, +} diff --git a/dfssc/cmd/impexp.go b/dfssc/cmd/impexp.go new file mode 100644 index 0000000000000000000000000000000000000000..21ce38620a234ce8235725fb8a0d090571d520f0 --- /dev/null +++ b/dfssc/cmd/impexp.go @@ -0,0 +1,96 @@ +package cmd + +import ( + "fmt" + "os" + + "dfss/dfssc/common" + "dfss/dfssc/user" + "github.com/spf13/cobra" +) + +// export the certificate and private key of the user +var exportCmd = &cobra.Command{ + Use: "export ", + Short: "export certificate and private key of the user to file c", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + _ = cmd.Usage() + os.Exit(1) + return + } + + 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 ", + Short: "import private key and certificate of the user from file c", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + _ = cmd.Usage() + os.Exit(1) + return + } + + 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) +} diff --git a/dfssc/new.go b/dfssc/cmd/new.go similarity index 61% rename from dfssc/new.go rename to dfssc/cmd/new.go index b630e16c6d829d0fd90062f2328509f10af16e00..a21655f7abd9624a461692487e8cfdfcaace0848 100644 --- a/dfssc/new.go +++ b/dfssc/cmd/new.go @@ -1,21 +1,26 @@ -package main +package cmd import ( "fmt" "os" "dfss/dfssc/sign" + "github.com/spf13/cobra" ) -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 diff --git a/dfssc/register.go b/dfssc/cmd/register.go similarity index 67% rename from dfssc/register.go rename to dfssc/cmd/register.go index c8efa87836c9fc3c0e2de70e36051a3676b19f21..db07d437c63b74041e50d2ac467b7e56374d6ceb 100644 --- a/dfssc/register.go +++ b/dfssc/cmd/register.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "bufio" @@ -10,40 +10,45 @@ 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) diff --git a/dfssc/cmd/root.go b/dfssc/cmd/root.go new file mode 100644 index 0000000000000000000000000000000000000000..e5d39d720d670b887e7a0e3604bd8fb62ec62a87 --- /dev/null +++ b/dfssc/cmd/root.go @@ -0,0 +1,54 @@ +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(dfss.VersionCmd, registerCmd, authCmd, newCmd, showCmd, fetchCmd, importCmd, exportCmd, signCmd) + +} diff --git a/dfssc/show.go b/dfssc/cmd/show.go similarity index 78% rename from dfssc/show.go rename to dfssc/cmd/show.go index 0286de0ba3fbafd78314ed1689b47b6d285b8ece..4a6e1fb8854efc6756a078e65418d083fc367870 100644 --- a/dfssc/show.go +++ b/dfssc/cmd/show.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "bytes" @@ -8,6 +8,7 @@ import ( "dfss/dfssc/common" "dfss/dfssp/contract" + "github.com/spf13/cobra" ) const contractShowTemplate = `UUID : {{.UUID}} @@ -22,22 +23,18 @@ 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 - } +var showCmd = &cobra.Command{ + Use: "show ", + Short: "print contract information from file c", + Run: showContract, +} - c, err := common.UnmarshalDFSSFile(data) - if err != nil { - fmt.Println("Corrupted file:", err) - return nil +func showContract(cmd *cobra.Command, args []string) { + if len(args) != 1 { + _ = cmd.Usage() + return } - return c -} -func showContract(args []string) { filename := args[0] c := getContract(filename) if c == nil { @@ -57,3 +54,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 +} diff --git a/dfssc/cmd/sign.go b/dfssc/cmd/sign.go new file mode 100644 index 0000000000000000000000000000000000000000..8c48390e0194ac81d51cca865a35f3d95d5d5f5c --- /dev/null +++ b/dfssc/cmd/sign.go @@ -0,0 +1,91 @@ +package cmd + +import ( + "fmt" + "os" + + "dfss/dfssc/sign" + "github.com/spf13/cobra" +) + +var signCmd = &cobra.Command{ + Use: "sign ", + Short: "sign contract from file c", + Run: func(cmd *cobra.Command, args []string) { + if len(args) != 1 { + _ = cmd.Usage() + os.Exit(1) + } + + 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) {} diff --git a/dfssc/common/viper_helper.go b/dfssc/common/viper_helper.go new file mode 100644 index 0000000000000000000000000000000000000000..2eccf59d6d4a708ff4b0921492b304c24a3da87d --- /dev/null +++ b/dfssc/common/viper_helper.go @@ -0,0 +1,33 @@ +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 +} diff --git a/dfssc/fetch.go b/dfssc/fetch.go deleted file mode 100644 index 08e6687ee9d053f75afe7afd57a1aa951ec9aa8d..0000000000000000000000000000000000000000 --- a/dfssc/fetch.go +++ /dev/null @@ -1,25 +0,0 @@ -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) - } -} diff --git a/dfssc/impexp.go b/dfssc/impexp.go deleted file mode 100644 index da8213445fa532842680d882169b8b7b15750c0f..0000000000000000000000000000000000000000 --- a/dfssc/impexp.go +++ /dev/null @@ -1,74 +0,0 @@ -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 - } -} diff --git a/dfssc/main.go b/dfssc/main.go index 05d5d93de92e5325e934f492ebae5ba7f307c941..87d4e8f18f930ad50255fe8ade633eb5f3bcbdac 100644 --- a/dfssc/main.go +++ b/dfssc/main.go @@ -1,92 +1,13 @@ 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 print contract information from file c") - fmt.Println(" export export certificate and private key of the user to file c") - fmt.Println(" import import private key and certificate from file c") - fmt.Println(" sign sign contract from file c") - - fmt.Println("\nFlags:") - flag.PrintDefaults() - - fmt.Println() - } -} - -type command struct { - nbArgs int - fn func([]string) -} - -var commands = map[string]command{ - "version": command{0, func([]string) { - fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH) - }}, - "register": command{0, registerUser}, - "auth": command{0, authUser}, - "new": command{0, newContract}, - "fetch": command{0, fetchContract}, - "show": command{1, showContract}, - "export": command{1, exportConf}, - "import": command{1, importConf}, - "sign": command{1, signContract}, -} - func main() { - flag.Parse() - arg := flag.Arg(0) - dapi.Configure(demo != "", demo, "client") - - c, ok := commands[arg] - - if !ok || flag.NArg()-1 < c.nbArgs { - flag.Usage() - return + if err := cmd.RootCmd.Execute(); err != nil { + os.Exit(1) } - - args := flag.Args() - args = append(args, "") - c.fn(args[1:]) } diff --git a/dfssc/security/auth.go b/dfssc/security/auth.go index 7d239ef028a825bc15c342eaaeba84782cde8c80..07cebd088b8d5604be65a3369ae3128049cae53b 100644 --- a/dfssc/security/auth.go +++ b/dfssc/security/auth.go @@ -3,15 +3,13 @@ package security import ( "crypto/rsa" "crypto/x509" + + "github.com/spf13/viper" ) // AuthContainer contains common information for TLS authentication. // Files are not loaded from the beginning, call LoadFiles to load them. type AuthContainer struct { - FileCA string - FileCert string - FileKey string - AddrPort string Passphrase string CA *x509.Certificate @@ -20,27 +18,23 @@ type AuthContainer struct { } // NewAuthContainer is a shortcut to build an AuthContainer -func NewAuthContainer(fileCA, fileCert, fileKey, addrPort, passphrase string) *AuthContainer { +func NewAuthContainer(passphrase string) *AuthContainer { return &AuthContainer{ - FileCA: fileCA, - FileCert: fileCert, - FileKey: fileKey, - AddrPort: addrPort, Passphrase: passphrase, } } // LoadFiles tries to load the required certificates and key for TLS authentication func (a *AuthContainer) LoadFiles() (ca *x509.Certificate, cert *x509.Certificate, key *rsa.PrivateKey, err error) { - ca, err = GetCertificate(a.FileCA) + ca, err = GetCertificate(viper.GetString("file_ca")) if err != nil { return } - cert, err = GetCertificate(a.FileCert) + cert, err = GetCertificate(viper.GetString("file_cert")) if err != nil { return } - key, err = GetPrivateKey(a.FileKey, a.Passphrase) + key, err = GetPrivateKey(viper.GetString("file_key"), a.Passphrase) a.CA = ca a.Cert = cert diff --git a/dfssc/security/request.go b/dfssc/security/request.go index 15396f289879325f76fec91e7e3cb2a84820ebbc..4361986f0b6d0a246e74f0ca4391fef332b93fd5 100644 --- a/dfssc/security/request.go +++ b/dfssc/security/request.go @@ -6,10 +6,12 @@ import ( "dfss/auth" "dfss/dfssc/common" "fmt" + + "github.com/spf13/viper" ) // GenerateKeys generate a pair of keys and save it to the disk -func GenerateKeys(bits int, passphrase, filename string) (*rsa.PrivateKey, error) { +func GenerateKeys(bits int, passphrase string) (*rsa.PrivateKey, error) { key, err := auth.GeneratePrivateKey(bits) if err != nil { return nil, err @@ -20,7 +22,7 @@ func GenerateKeys(bits int, passphrase, filename string) (*rsa.PrivateKey, error return nil, err } - err = common.SaveToDisk(pem, filename) + err = common.SaveToDisk(pem, viper.GetString("file_key")) if err != nil { return nil, err } diff --git a/dfssc/security/security_test.go b/dfssc/security/security_test.go index 2a9c6440d547cb23203e4170e2ea83707f95e070..64b733bdfc481f49245a0ab749ebd52ffe2077c6 100644 --- a/dfssc/security/security_test.go +++ b/dfssc/security/security_test.go @@ -7,6 +7,7 @@ import ( "path/filepath" "testing" + "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) @@ -32,8 +33,9 @@ var path = os.TempDir() // Test the generation of keys func TestGenerateKeys(t *testing.T) { fkey := filepath.Join(path, "genKey.pem") + viper.Set("file_key", fkey) - rsa, err := GenerateKeys(512, "pwd", fkey) + rsa, err := GenerateKeys(512, "pwd") assert.True(t, err == nil, "An error has been raised during generation") assert.True(t, rsa != nil, "RSA key should not be nil") assert.True(t, common.FileExists(fkey), "File is missing") @@ -43,8 +45,9 @@ func TestGenerateKeys(t *testing.T) { // Test the generation of a certificate request func TestCertificateRequest(t *testing.T) { fkey := filepath.Join(path, "genCsr.pem") + viper.Set("file_key", fkey) - rsa, err := GenerateKeys(512, "pwd", fkey) + rsa, err := GenerateKeys(512, "pwd") defer common.DeleteQuietly(fkey) assert.True(t, err == nil, "An error has been raised during generation") assert.True(t, rsa != nil, "RSA key should not be nil") @@ -58,8 +61,9 @@ func TestCertificateRequest(t *testing.T) { // Test saving rsa key on the disk func TestDumpingKey(t *testing.T) { fkey := filepath.Join(path, "dumpKey.pem") + viper.Set("file_key", fkey) - rsa, err := GenerateKeys(512, "pwd", fkey) + rsa, err := GenerateKeys(512, "pwd") defer common.DeleteQuietly(fkey) assert.True(t, err == nil, "An error has been raised during generation") diff --git a/dfssc/sign.go b/dfssc/sign.go deleted file mode 100644 index aff20e51ad683fea43f5c848dd34824e02f64cba..0000000000000000000000000000000000000000 --- a/dfssc/sign.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "dfss/dfssc/sign" -) - -func signContract(args []string) { - filename := args[0] - fmt.Println("You are going to sign the following contract:") - showContract(args) - - contract := getContract(filename) - if contract == nil { - os.Exit(1) - } - - var passphrase string - _ = readPassword(&passphrase, false) - - // Preparation - manager, err := sign.NewSignatureManager(fca, fcert, fkey, addrPort, passphrase, localPort, 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) {} diff --git a/dfssc/sign/create.go b/dfssc/sign/create.go index be390d7272cace19b80ddf03ad4925164d08cbb2..09095892906644734c7f1b39d1d9000965fe07b1 100644 --- a/dfssc/sign/create.go +++ b/dfssc/sign/create.go @@ -5,10 +5,13 @@ import ( "io/ioutil" "path/filepath" + "github.com/spf13/viper" + "dfss/dfssc/common" "dfss/dfssc/security" "dfss/dfssp/api" "dfss/net" + "golang.org/x/net/context" ) @@ -23,9 +26,9 @@ type CreateManager struct { } // SendNewContract tries to create a contract on the platform and returns an error or nil -func SendNewContract(fileCA, fileCert, fileKey, addrPort, passphrase, filepath, comment string, signers []string) error { +func SendNewContract(passphrase, filepath, comment string, signers []string) error { m := &CreateManager{ - auth: security.NewAuthContainer(fileCA, fileCert, fileKey, addrPort, passphrase), + auth: security.NewAuthContainer(passphrase), filepath: filepath, comment: comment, signers: signers, @@ -66,7 +69,7 @@ func (m *CreateManager) sendRequest() (*api.ErrorCode, error) { return nil, err } - conn, err := net.Connect(m.auth.AddrPort, cert, key, ca) + conn, err := net.Connect(viper.GetString("platform_addrport"), cert, key, ca) if err != nil { return nil, err } diff --git a/dfssc/sign/create_test.go b/dfssc/sign/create_test.go index bcd630b7edf652be7c732edeeb9c7911b689545b..f9a29a3148b9e56992ad8f4a6411f7ce08037812 100644 --- a/dfssc/sign/create_test.go +++ b/dfssc/sign/create_test.go @@ -10,6 +10,8 @@ import ( "dfss/auth" "dfss/mockp/server" + + "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) @@ -33,6 +35,12 @@ func TestMain(m *testing.M) { os.Exit(1) } + // Init conf + viper.Set("file_key", fkey) + viper.Set("file_cert", fcert) + viper.Set("file_ca", fca) + viper.Set("platform_addrport", addrPort) + ca, _ := auth.PEMToCertificate(caData) key, _ := auth.PEMToPrivateKey(keyData) @@ -44,10 +52,10 @@ func TestMain(m *testing.M) { } func TestNewCreateManager(t *testing.T) { - err := SendNewContract(fca, fcert, fkey, addrPort, "password", fcontract, "success", []string{"a@example.com", "b@example.com"}) + err := SendNewContract("password", fcontract, "success", []string{"a@example.com", "b@example.com"}) assert.Equal(t, nil, err) - err = SendNewContract(fca, fcert, fkey, addrPort, "password", fcontract, "warning", []string{"a@example.com", "b@example.com"}) + err = SendNewContract("password", fcontract, "warning", []string{"a@example.com", "b@example.com"}) assert.Equal(t, "Operation succeeded with a warning message: Some users are not ready yet", err.Error()) } diff --git a/dfssc/sign/fetch.go b/dfssc/sign/fetch.go index 45e152940a17656d58e54ffc064b46ec89179cf6..9976c6b9ed068c79f3bcc73563d194b8fa2ae806 100644 --- a/dfssc/sign/fetch.go +++ b/dfssc/sign/fetch.go @@ -3,22 +3,25 @@ package sign import ( "io/ioutil" + "github.com/spf13/viper" + "dfss/dfssc/common" "dfss/dfssc/security" "dfss/dfssp/api" "dfss/net" + "golang.org/x/net/context" ) // FetchContract tries to download contract metadata from specified uuid, and stores the resulting json at path -func FetchContract(fileCA, fileCert, fileKey, addrPort, passphrase, uuid, path string) error { - auth := security.NewAuthContainer(fileCA, fileCert, fileKey, addrPort, passphrase) +func FetchContract(passphrase, uuid, path string) error { + auth := security.NewAuthContainer(passphrase) ca, cert, key, err := auth.LoadFiles() if err != nil { return err } - conn, err := net.Connect(auth.AddrPort, cert, key, ca) + conn, err := net.Connect(viper.GetString("platform_addrport"), cert, key, ca) if err != nil { return err } diff --git a/dfssc/sign/fetch_test.go b/dfssc/sign/fetch_test.go index 73a0830fad28a892de4b2fbd349a8bef0b2eb51f..2d8d924079477faeec9b21e51448f0b489920642 100644 --- a/dfssc/sign/fetch_test.go +++ b/dfssc/sign/fetch_test.go @@ -20,7 +20,7 @@ func TestFetchContractWrongUUID(t *testing.T) { func checkFetchResult(t *testing.T, uuid string, errExpected bool, content string) { file, _ := ioutil.TempFile("", "") defer func() { _ = os.Remove(file.Name()) }() - err := FetchContract(fca, fcert, fkey, addrPort, "password", uuid, file.Name()) + err := FetchContract("password", uuid, file.Name()) if errExpected { assert.NotEqual(t, nil, err) } else { diff --git a/dfssc/sign/starter.go b/dfssc/sign/starter.go index 23a86ec203981010bbba76dee363ed9d90111490..bb3297ed1a5ce428358548d1ee93ea1f57131618 100644 --- a/dfssc/sign/starter.go +++ b/dfssc/sign/starter.go @@ -8,6 +8,8 @@ import ( "sync" "time" + "github.com/spf13/viper" + "dfss" cAPI "dfss/dfssc/api" "dfss/dfssc/common" @@ -16,6 +18,7 @@ import ( pAPI "dfss/dfssp/api" "dfss/dfssp/contract" "dfss/net" + "golang.org/x/net/context" "google.golang.org/grpc" ) @@ -26,7 +29,6 @@ const chanBufferSize = 100 // SignatureManager handles the signature of a contract. type SignatureManager struct { auth *security.AuthContainer - localPort int contract *contract.JSON // contains the contractUUID, the list of the signers' hashes, the hash of the contract platform pAPI.PlatformClient platformConn *grpc.ClientConn @@ -58,11 +60,10 @@ type Archives struct { } // NewSignatureManager populates a SignatureManager and connects to the platform. -func NewSignatureManager(fileCA, fileCert, fileKey, addrPort, passphrase string, port int, c *contract.JSON) (*SignatureManager, error) { +func NewSignatureManager(passphrase string, c *contract.JSON) (*SignatureManager, error) { m := &SignatureManager{ - auth: security.NewAuthContainer(fileCA, fileCert, fileKey, addrPort, passphrase), - localPort: port, - contract: c, + auth: security.NewAuthContainer(passphrase), + contract: c, archives: &Archives{ sentPromises: make([]*cAPI.Promise, 0), receivedPromises: make([]*cAPI.Promise, 0), @@ -80,9 +81,9 @@ func NewSignatureManager(fileCA, fileCert, fileKey, addrPort, passphrase string, dAPI.SetIdentifier(m.mail) m.cServer = m.GetServer() - go func() { log.Fatalln(net.Listen("0.0.0.0:"+strconv.Itoa(port), m.cServer)) }() + go func() { log.Fatalln(net.Listen("0.0.0.0:"+strconv.Itoa(viper.GetInt("local_port")), m.cServer)) }() - conn, err := net.Connect(m.auth.AddrPort, m.auth.Cert, m.auth.Key, m.auth.CA) + conn, err := net.Connect(viper.GetString("platform_addrport"), m.auth.Cert, m.auth.Key, m.auth.CA) if err != nil { return nil, err } @@ -105,7 +106,7 @@ func NewSignatureManager(fileCA, fileCert, fileKey, addrPort, passphrase string, func (m *SignatureManager) ConnectToPeers() error { stream, err := m.platform.JoinSignature(context.Background(), &pAPI.JoinSignatureRequest{ ContractUuid: m.contract.UUID, - Port: uint32(m.localPort), + Port: uint32(viper.GetInt("local_port")), }) if err != nil { return err diff --git a/dfssc/user/authentication.go b/dfssc/user/authentication.go index f19ed35d6b72e2d3c9fac4982cfe32be6e5f216c..a17d11a1055212ffd3c6901c8db8e196b3203fe1 100644 --- a/dfssc/user/authentication.go +++ b/dfssc/user/authentication.go @@ -5,32 +5,31 @@ import ( "regexp" "time" + "github.com/spf13/viper" + "dfss/dfssc/common" "dfss/dfssc/security" pb "dfss/dfssp/api" "dfss/net" "errors" + "golang.org/x/net/context" "google.golang.org/grpc" ) // AuthManager handles the authentication of a user type AuthManager struct { - fileCA string - fileCert string - addrPort string - mail string - token string + viper *viper.Viper + mail string + token string } // NewAuthManager creates a new authentication manager with the given parameters -func NewAuthManager(fileCA, fileCert, addrPort, mail, token string) (*AuthManager, error) { +func NewAuthManager(mail, token string, viper *viper.Viper) (*AuthManager, error) { m := &AuthManager{ - fileCA: fileCA, - fileCert: fileCert, - addrPort: addrPort, - mail: mail, - token: token, + viper: viper, + mail: mail, + token: token, } if err := m.checkValidParams(); err != nil { @@ -54,15 +53,17 @@ func (m *AuthManager) checkValidParams() error { } func (m *AuthManager) checkFilePresence() error { - if b := common.FileExists(m.fileCert); b { - return errors.New("A certificate is already present at path " + m.fileCert) + fileCert := m.viper.GetString("file_cert") + if b := common.FileExists(fileCert); b { + return errors.New("A certificate is already present at path " + fileCert) } - if b := common.FileExists(m.fileCA); !b { - return errors.New("You need the certificate of the platform at path " + m.fileCA) + fileCA := m.viper.GetString("file_ca") + if b := common.FileExists(fileCA); !b { + return errors.New("You need the certificate of the platform at path " + fileCA) } - data, err := security.GetCertificate(m.fileCA) + data, err := security.GetCertificate(fileCA) if err != nil { return err } @@ -87,7 +88,7 @@ func (m *AuthManager) Authenticate() error { // Creates the associated authentication request and sends it to the platform grpc server func (m *AuthManager) sendRequest() (*pb.RegisteredUser, error) { - client, err := connect(m.fileCA, m.addrPort) + client, err := connect() if err != nil { return nil, err } @@ -113,5 +114,5 @@ func (m *AuthManager) sendRequest() (*pb.RegisteredUser, error) { func (m *AuthManager) evaluateResponse(response *pb.RegisteredUser) error { cert := []byte(response.ClientCert) - return ioutil.WriteFile(m.fileCert, cert, 0600) + return ioutil.WriteFile(m.viper.GetString("file_cert"), cert, 0600) } diff --git a/dfssc/user/authentication_test.go b/dfssc/user/authentication_test.go index 3bd00981acabc3c33c26a77e0d0c176051281451..36ee50256c94d3877209ab5a2786fd14ae1e5919 100644 --- a/dfssc/user/authentication_test.go +++ b/dfssc/user/authentication_test.go @@ -3,30 +3,36 @@ package user import ( "dfss/dfssc/common" "fmt" - "github.com/stretchr/testify/assert" "os" "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" ) +func mockb(fca, fcert, addrPort string) *viper.Viper { + return common.MockViper("file_ca", fca, "file_cert", fcert, "platform_addrport", addrPort) +} + func TestAuthenticationValidation(t *testing.T) { - _, err := NewAuthManager("fca", fcert, addrPort, "dummy", "token") + _, err := NewAuthManager("dummy", "token", mockb("fca", fcert, addrPort)) assert.True(t, err != nil, "Email is invalid") f, _ := os.Create(fcert) _ = f.Close() - _, err = NewAuthManager("fca", fcert, addrPort, "mail@mail.mail", "token") + _, err = NewAuthManager("mail@mail.mail", "token", mockb("fca", fcert, addrPort)) assert.True(t, err != nil, "Cert file already there") _ = os.Remove(fcert) - _, err = NewAuthManager("fca", fcert, addrPort, "mail@mail.mail", "token") + _, err = NewAuthManager("mail@mail.mail", "token", mockb("fca", fcert, addrPort)) assert.True(t, err != nil, "CA file not there") - _, err = NewAuthManager(fca, fcert, addrPort, "mail@mail.mail", "token") + _, err = NewAuthManager("mail@mail.mail", "token", mockb(fca, fcert, addrPort)) assert.Equal(t, err, nil) } func ExampleAuthenticate() { - manager, err := NewAuthManager(fca, fcert, addrPort, "mail@mail.mail", "token") + manager, err := NewAuthManager("mail@mail.mail", "token", mockb(fca, fcert, addrPort)) if err != nil { fmt.Println(err.Error()) } diff --git a/dfssc/user/client.go b/dfssc/user/client.go index 5390d654e6c46365264b2307036231dafbf7b7e9..dec55d8789d7998032ed99efe331c6ba0ca74d00 100644 --- a/dfssc/user/client.go +++ b/dfssc/user/client.go @@ -2,14 +2,17 @@ package user import ( + "dfss/dfssc/common" "dfss/dfssc/security" pb "dfss/dfssp/api" "dfss/net" + + "github.com/spf13/viper" ) // Register a user using the provided parameters -func Register(fileCA, fileCert, fileKey, addrPort, passphrase, country, organization, unit, mail string, bits int) error { - manager, err := NewRegisterManager(fileCA, fileCert, fileKey, addrPort, passphrase, country, organization, unit, mail, bits) +func Register(passphrase, country, organization, unit, mail string, bits int) error { + manager, err := NewRegisterManager(passphrase, country, organization, unit, mail, bits, common.SubViper("file_key", "file_cert", "file_ca")) if err != nil { return err } @@ -17,21 +20,21 @@ func Register(fileCA, fileCert, fileKey, addrPort, passphrase, country, organiza } // Authenticate a user using the provided parameters -func Authenticate(fileCA, fileCert, addrPort, mail, token string) error { - manager, err := NewAuthManager(fileCA, fileCert, addrPort, mail, token) +func Authenticate(mail, token string) error { + manager, err := NewAuthManager(mail, token, common.SubViper("file_ca", "file_cert")) if err != nil { return err } return manager.Authenticate() } -func connect(fileCA, addrPort string) (pb.PlatformClient, error) { - ca, err := security.GetCertificate(fileCA) +func connect() (pb.PlatformClient, error) { + ca, err := security.GetCertificate(viper.GetString("file_ca")) if err != nil { return nil, err } - conn, err := net.Connect(addrPort, nil, nil, ca) + conn, err := net.Connect(viper.GetString("platform_addrport"), nil, nil, ca) if err != nil { return nil, err } diff --git a/dfssc/user/config.go b/dfssc/user/config.go index ee0a0196acd3e9771d9cbdec457b82f883a9183e..ce4210252d1892e6c1390af95a4bb8d8717d2189 100644 --- a/dfssc/user/config.go +++ b/dfssc/user/config.go @@ -6,6 +6,8 @@ import ( "dfss/dfssc/security" "encoding/json" "fmt" + + "github.com/spf13/viper" ) // Config represents the config file to be marshalled in json @@ -18,11 +20,13 @@ type Config struct { // NewConfig creates a new config object from the key and certificate provided // The validity of those is checked later -func NewConfig(keyFile, certFile string) (*Config, error) { +func NewConfig(viper *viper.Viper) (*Config, error) { + keyFile := viper.GetString("file_key") if !common.FileExists(keyFile) { return nil, fmt.Errorf("No such file: %s", keyFile) } + certFile := viper.GetString("file_cert") if !common.FileExists(certFile) { return nil, fmt.Errorf("No such file: %s", certFile) } diff --git a/dfssc/user/config_test.go b/dfssc/user/config_test.go index dc814e5f7c181185ad25a7006f4a7c4ca2f0e84a..7d26c9418ba4aba240f89e332e9c8b269e12f5e6 100644 --- a/dfssc/user/config_test.go +++ b/dfssc/user/config_test.go @@ -45,15 +45,15 @@ func TestInvalidFiles(t *testing.T) { certFile := filepath.Join(cPath, "invalidCert.pem") defer deleteFiles(keyFile, certFile, "invalidConf.pem") - _, err := NewConfig("inexistantKey", "inexistantCert") + _, err := NewConfig(common.MockViper("file_key", "inexistantKey", "file_cert", "inexistantCert")) assert.True(t, err != nil, "No key file nor cert file, expected error") _ = common.SaveStringToDisk(fmt.Sprintf("%s", []byte(keyFixture)), keyFile) - _, err = NewConfig(keyFile, "inexistantCert") + _, err = NewConfig(common.MockViper("file_key", keyFile, "file_cert", "inexistantCert")) assert.True(t, err != nil, "No cert file, expected error") _ = security.SaveCertificate(fmt.Sprintf("%s", []byte(certFixture)), certFile) - _, err = NewConfig(keyFile, certFile) + _, err = NewConfig(common.MockViper("file_key", keyFile, "file_cert", certFile)) assert.True(t, err == nil, "Expected no error, files are present and valid") } @@ -61,6 +61,7 @@ func TestInvalidFiles(t *testing.T) { func TestErrorDumpingConfig(t *testing.T) { keyFile := filepath.Join(cPath, "privKey.pem") certFile := filepath.Join(cPath, "cert.pem") + mockViper := common.MockViper("file_key", keyFile, "file_cert", certFile) defer deleteFiles(keyFile, certFile, "invalidConf.pem") err := common.SaveStringToDisk(fmt.Sprintf("%s", []byte(keyFixture)), keyFile) @@ -69,7 +70,7 @@ func TestErrorDumpingConfig(t *testing.T) { err = security.SaveCertificate(fmt.Sprintf("%s", []byte(certFixture)), certFile) assert.True(t, err == nil, "Expected no error, cert is valid") - config, err := NewConfig(keyFile, certFile) + config, err := NewConfig(mockViper) assert.True(t, err == nil, "Expected no error, files are present and valid") err = config.SaveConfigToFile("file", "abc", "") @@ -80,7 +81,7 @@ func TestErrorDumpingConfig(t *testing.T) { common.DeleteQuietly(keyFile) _ = common.SaveStringToDisk("Invalid key", keyFile) - config, _ = NewConfig(keyFile, certFile) + config, _ = NewConfig(mockViper) err = config.SaveConfigToFile("file", "passphrase", "passphrase") assert.True(t, err != nil, "Expected an error, private key is invalid") @@ -88,7 +89,7 @@ func TestErrorDumpingConfig(t *testing.T) { common.DeleteQuietly(keyFile) _ = common.SaveStringToDisk(fmt.Sprintf("%s", []byte(keyFixture)), keyFile) _ = common.SaveStringToDisk("Invalid certificate", certFile) - config, _ = NewConfig(keyFile, certFile) + config, _ = NewConfig(mockViper) err = config.SaveConfigToFile("file", "passphrase", "passphrase") assert.True(t, err != nil, "Expected an error, certificate is invalid") @@ -108,7 +109,7 @@ func TestDumpingFile(t *testing.T) { err = security.SaveCertificate(fmt.Sprintf("%s", []byte(certFixture)), certFile) assert.True(t, err == nil, "Expected no error, cert is valid") - config, err := NewConfig(keyFile, certFile) + config, err := NewConfig(common.MockViper("file_key", keyFile, "file_cert", certFile)) assert.True(t, err == nil, "Expected no error, files are present and valid") err = config.SaveConfigToFile(configPath, "passphrase", "") @@ -137,7 +138,7 @@ func TestErrorDecodeFile(t *testing.T) { _, err = DecodeConfiguration(keyFile, "pas", "") assert.True(t, err != nil, "Passphrase is invalid, should be at least 4 char long") - config, err := NewConfig(keyFile, certFile) + config, err := NewConfig(common.MockViper("file_key", keyFile, "file_cert", certFile)) assert.True(t, err == nil, "Expected no error, files are present and valid") err = config.SaveConfigToFile(configPath, "passphrase", "") @@ -159,7 +160,7 @@ func TestDecodeConfig(t *testing.T) { _ = common.SaveStringToDisk(fmt.Sprintf("%s", []byte(keyFixture)), keyFile) _ = security.SaveCertificate(fmt.Sprintf("%s", []byte(certFixture)), certFile) - config, err := NewConfig(keyFile, certFile) + config, err := NewConfig(common.MockViper("file_key", keyFile, "file_cert", certFile)) assert.True(t, err == nil, "Expected no error, files are present and valid") err = config.SaveConfigToFile(configPath, "passphrase", "") @@ -186,7 +187,7 @@ func TestSaveFilesToDisk(t *testing.T) { _ = common.SaveStringToDisk(fmt.Sprintf("%s", []byte(keyFixture)), keyFile) _ = security.SaveCertificate(fmt.Sprintf("%s", []byte(certFixture)), certFile) - config, err := NewConfig(keyFile, certFile) + config, err := NewConfig(common.MockViper("file_key", keyFile, "file_cert", certFile)) assert.True(t, err == nil, "Expected no error, files are present and valid") err = config.SaveUserInformations() diff --git a/dfssc/user/register.go b/dfssc/user/register.go index 85575df83c264e120e2ad206bceded881eb15281..071729c2cf7f8131f83fac736c29eb625354c341 100644 --- a/dfssc/user/register.go +++ b/dfssc/user/register.go @@ -5,20 +5,20 @@ import ( "regexp" "time" + "github.com/spf13/viper" + "dfss/dfssc/common" "dfss/dfssc/security" pb "dfss/dfssp/api" "dfss/net" + "golang.org/x/net/context" "google.golang.org/grpc" ) // RegisterManager handles the registration of a user type RegisterManager struct { - fileCA string - fileCert string - fileKey string - addrPort string + *viper.Viper passphrase string country string organization string @@ -28,19 +28,8 @@ type RegisterManager struct { } // NewRegisterManager return a new Register Manager to register a user -func NewRegisterManager(fileCA, fileCert, fileKey, addrPort, passphrase, country, organization, unit, mail string, bits int) (*RegisterManager, error) { - m := &RegisterManager{ - fileCA: fileCA, - fileCert: fileCert, - fileKey: fileKey, - addrPort: addrPort, - passphrase: passphrase, - country: country, - organization: organization, - unit: unit, - mail: mail, - bits: bits, - } +func NewRegisterManager(passphrase, country, organization, unit, mail string, bits int, v *viper.Viper) (*RegisterManager, error) { + m := &RegisterManager{v, passphrase, country, organization, unit, mail, bits} if err := m.checkValidParams(); err != nil { return nil, err @@ -71,23 +60,26 @@ func (m *RegisterManager) checkValidParams() error { // Check the CA is present and valid // Check there is not a duplicate file func (m *RegisterManager) checkFilePresence() error { - if b := common.FileExists(m.fileKey); b { - return errors.New("A private key is already present at path " + m.fileKey) + fileKey := m.GetString("file_key") + if b := common.FileExists(fileKey); b { + return errors.New("A private key is already present at path " + fileKey) } - if b := common.FileExists(m.fileCert); b { - return errors.New("A certificate is already present at path " + m.fileCert) + fileCert := m.GetString("file_cert") + if b := common.FileExists(fileCert); b { + return errors.New("A certificate is already present at path " + fileCert) } - if m.fileKey == m.fileCert { + if fileKey == fileCert { return errors.New("Cannot store certificate and key in the same file") } - if b := common.FileExists(m.fileCA); !b { - return errors.New("You need the certificate of the platform at path " + m.fileCA) + fileCA := m.GetString("file_ca") + if b := common.FileExists(fileCA); !b { + return errors.New("You need the certificate of the platform at path " + fileCA) } - data, err := security.GetCertificate(m.fileCA) + data, err := security.GetCertificate(fileCA) if err != nil { return err } @@ -101,21 +93,22 @@ func (m *RegisterManager) checkFilePresence() error { // GetCertificate handles the creation of a certificate, delete private key upon failure func (m *RegisterManager) GetCertificate() error { + fileKey := m.GetString("file_key") request, err := m.buildCertificateRequest() if err != nil { - common.DeleteQuietly(m.fileKey) + common.DeleteQuietly(fileKey) return err } code, err := m.sendRequest(request) if err != nil { - common.DeleteQuietly(m.fileKey) + common.DeleteQuietly(fileKey) return err } err = common.EvaluateErrorCodeResponse(code) if err != nil { - common.DeleteQuietly(m.fileKey) + common.DeleteQuietly(fileKey) return err } @@ -124,7 +117,7 @@ func (m *RegisterManager) GetCertificate() error { // Builds a certificate request func (m *RegisterManager) buildCertificateRequest() (string, error) { - key, err := security.GenerateKeys(m.bits, m.passphrase, m.fileKey) + key, err := security.GenerateKeys(m.bits, m.passphrase) if err != nil { return "", err } @@ -139,7 +132,7 @@ func (m *RegisterManager) buildCertificateRequest() (string, error) { // Send the request and returns the response func (m *RegisterManager) sendRequest(certRequest string) (*pb.ErrorCode, error) { - client, err := connect(m.fileCA, m.addrPort) + client, err := connect() if err != nil { return nil, err } diff --git a/dfssc/user/register_test.go b/dfssc/user/register_test.go index c166854aca7f238feba686f112954fcac7bd8ab7..26dab93a03c853ab5df66c829e73307018480f75 100644 --- a/dfssc/user/register_test.go +++ b/dfssc/user/register_test.go @@ -2,6 +2,7 @@ package user import ( "dfss/auth" + "dfss/dfssc/common" "dfss/dfssc/security" "dfss/mockp/server" "fmt" @@ -10,6 +11,7 @@ import ( "testing" "time" + "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) @@ -46,6 +48,10 @@ var fcert = filepath.Join(path, "cert.pem") var fkey = filepath.Join(path, "key.pem") var addrPort = "localhost:9000" +func mock(fca, fcert, fkey string) *viper.Viper { + return common.MockViper("file_key", fkey, "file_cert", fcert, "file_ca", fca) +} + // Main test function func TestMain(m *testing.M) { // Generate a certificate and save it on the disk @@ -54,6 +60,12 @@ func TestMain(m *testing.M) { ca, _ := auth.PEMToCertificate([]byte(caFixture)) skey, _ := auth.PEMToPrivateKey([]byte(serverKeyFixture)) + // Init config + viper.Set("file_ca", fca) + viper.Set("file_cert", fcert) + viper.Set("file_key", fkey) + viper.Set("platform_addrport", addrPort) + // Start the platform mock go server.Run(ca, skey, addrPort) time.Sleep(2 * time.Second) @@ -66,23 +78,23 @@ func TestMain(m *testing.M) { // Test the validation of the fields func TestRegisterValidation(t *testing.T) { - _, err := NewRegisterManager(fca, fcert, fkey, addrPort, "password", "FR", "organization", "unit", "dummy", 2048) + _, err := NewRegisterManager("password", "FR", "organization", "unit", "dummy", 2048, mock(fca, fcert, fkey)) assert.True(t, err != nil, "Email is invalid") - _, err = NewRegisterManager(fca, fkey, fkey, addrPort, "password", "FR", "organization", "unit", "mpcs@dfss.io", 2048) + _, err = NewRegisterManager("password", "FR", "organization", "unit", "mpcs@dfss.io", 2048, mock(fca, fkey, fkey)) assert.True(t, err != nil, "Cert file is the same as key file") - _, err = NewRegisterManager("inexistant.pem", fcert, fkey, addrPort, "password", "FR", "organization", "unit", "mpcs@dfss.io", 2048) + _, err = NewRegisterManager("password", "FR", "organization", "unit", "mpcs@dfss.io", 2048, mock("inexistant.pem", fcert, fkey)) assert.True(t, err != nil, "CA file is invalid") f, _ := os.Create(fcert) _ = f.Close() - _, err = NewRegisterManager(fca, fcert, fkey, addrPort, "password", "FR", "organization", "unit", "mpcs@dfss.io", 2048) + _, err = NewRegisterManager("password", "FR", "organization", "unit", "mpcs@dfss.io", 2048, mock(fca, fcert, fkey)) assert.True(t, err != nil, "Cert file already exist") k, _ := os.Create(fkey) _ = k.Close() - _, err = NewRegisterManager(fca, fcert, fkey, addrPort, "password", "FR", "organization", "unit", "mpcs@dfss.io", 2048) + _, err = NewRegisterManager("password", "FR", "organization", "unit", "mpcs@dfss.io", 2048, mock(fca, fcert, fkey)) assert.True(t, err != nil, "Key file already exist") _ = os.Remove(fcert) @@ -92,7 +104,7 @@ func TestRegisterValidation(t *testing.T) { // Test the error codes received from the mock // Only the SUCCESS code should not raise an error func TestGetCertificate(t *testing.T) { - manager, err := NewRegisterManager(fca, fcert, fkey, addrPort, "password", "FR", "organization", "unit", "dfss@success.io", 2048) + manager, err := NewRegisterManager("password", "FR", "organization", "unit", "dfss@success.io", 2048, mock(fca, fcert, fkey)) assert.True(t, err == nil, "An error occurred while processing") err = manager.GetCertificate() assert.True(t, err == nil, "An error occurred while getting the certificate") @@ -106,7 +118,7 @@ func TestGetCertificate(t *testing.T) { // Test an invalid error code and check we get an error func testRegisterInvalidResponse(t *testing.T, mail string) { - manager, err := NewRegisterManager(fca, fcert+mail, fkey+mail, addrPort, "password", "FR", "organization", "unit", mail, 2048) + manager, err := NewRegisterManager("password", "FR", "organization", "unit", mail, 2048, mock(fca, fcert+mail, fkey+mail)) assert.True(t, err == nil, "An error occurred while processing") err = manager.GetCertificate() diff --git a/dfssd/cmd/gui.go b/dfssd/cmd/gui.go new file mode 100644 index 0000000000000000000000000000000000000000..bb26a0f0aadfbd3cf562cae29149d546a041836b --- /dev/null +++ b/dfssd/cmd/gui.go @@ -0,0 +1,29 @@ +package cmd + +import ( + "strconv" + + "dfss/dfssd/gui" + "dfss/dfssd/server" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/visualfc/goqt/ui" +) + +var guiCmd = &cobra.Command{ + Use: "gui", + Short: "start the demonstrator with a gui", + Run: func(cmd *cobra.Command, args []string) { + addrPort := "0.0.0.0:" + strconv.Itoa(viper.GetInt("port")) + ui.Run(func() { + window := gui.NewWindow() + go func() { + err := server.Listen(addrPort, window.AddEvent) + if err != nil { + window.Log("!! " + err.Error()) + } + }() + window.Show() + }) + }, +} diff --git a/dfssd/cmd/nogui.go b/dfssd/cmd/nogui.go new file mode 100644 index 0000000000000000000000000000000000000000..58ed3cdbc0e1b7b17ee5a904dbab645183e9747f --- /dev/null +++ b/dfssd/cmd/nogui.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "fmt" + "os" + "strconv" + + "dfss/dfssd/api" + "dfss/dfssd/server" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var noguiCmd = &cobra.Command{ + Use: "nogui", + Short: "start demonstrator without GUI", + Run: func(cmd *cobra.Command, args []string) { + addrPort := "0.0.0.0:" + strconv.Itoa(viper.GetInt("port")) + + fmt.Println("Listening on " + addrPort) + fn := func(v *api.Log) { + fmt.Printf("[%d] %s: %s\n", v.Timestamp, v.Identifier, v.Log) + } + err := server.Listen(addrPort, fn) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + }, +} diff --git a/dfssd/cmd/root.go b/dfssd/cmd/root.go new file mode 100644 index 0000000000000000000000000000000000000000..37149c182fd301ac5a46fcc51bc5613d171eeea3 --- /dev/null +++ b/dfssd/cmd/root.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "dfss" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// RootCmd is the main command for the dfssd application +var RootCmd = &cobra.Command{ + Use: "dfssd", + Short: "Demonstrator for the DFSS project", + Long: "Demonstrator v" + dfss.Version + ` for the +Distributed Fair Signing System project + +Debug tool to trace remote transmissions`, + Run: guiCmd.Run, +} + +func init() { + // Add flag to the command + RootCmd.PersistentFlags().IntP("port", "p", 9099, "port to use for listening transmissions") + + // Bind the flag to viper + _ = viper.BindPFlag("port", RootCmd.PersistentFlags().Lookup("port")) + + // Register subcommands + RootCmd.AddCommand(dfss.VersionCmd, noguiCmd, guiCmd) +} diff --git a/dfssd/main.go b/dfssd/main.go index 52343f4003311f9d702d039434c4357b50137272..5d4a7215c25362c8e79e2dde623b7cb7e28046d0 100644 --- a/dfssd/main.go +++ b/dfssd/main.go @@ -1,76 +1,13 @@ package main import ( - "flag" - "fmt" "os" - "runtime" - "strconv" - "dfss" - "dfss/dfssd/api" - "dfss/dfssd/gui" - "dfss/dfssd/server" - "github.com/visualfc/goqt/ui" + "dfss/dfssd/cmd" ) -var ( - port int -) - -func init() { - - flag.IntVar(&port, "p", 3000, "Network port used") - - flag.Usage = func() { - fmt.Println("DFSS demonstrator v" + dfss.Version) - fmt.Println("Debug tool to check remote transmissions") - - fmt.Println("\nUsage:") - fmt.Println(" dfssd [flags] command") - - fmt.Println("\nThe commands are:") - fmt.Println(" help print this help") - fmt.Println(" version print dfss client version") - fmt.Println(" nogui start demonstrator server without GUI") - fmt.Println(" gui start demonstrator server with GUI") - - fmt.Println("\nFlags:") - flag.PrintDefaults() - - fmt.Println() - } -} - func main() { - flag.Parse() - command := flag.Arg(0) - addrPort := "0.0.0.0:" + strconv.Itoa(port) - - switch command { - case "help": - flag.Usage() - case "version": - fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH) - case "nogui": - fmt.Println("Listening on " + addrPort) - fn := func(v *api.Log) { - fmt.Printf("[%d] %s: %s\n", v.Timestamp, v.Identifier, v.Log) - } - err := server.Listen(addrPort, fn) - if err != nil { - os.Exit(1) - } - default: - ui.Run(func() { - window := gui.NewWindow() - go func() { - err := server.Listen(addrPort, window.AddEvent) - if err != nil { - window.Log("!! " + err.Error()) - } - }() - window.Show() - }) + if err := cmd.RootCmd.Execute(); err != nil { + os.Exit(1) } } diff --git a/dfssp/authority/rootCA.go b/dfssp/authority/rootCA.go index c1ff0dd4150ed6d9183eafd2bd3b78650867f7e7..d68db174be62bf0b9b894e3bdb5d825e98ade810 100644 --- a/dfssp/authority/rootCA.go +++ b/dfssp/authority/rootCA.go @@ -7,14 +7,9 @@ import ( "os" "path/filepath" - "dfss/auth" -) + "github.com/spf13/viper" -const ( - // PkeyFileName is the private key file default name - PkeyFileName = "dfssp_pkey.pem" - // RootCAFileName is the root certificate file default name - RootCAFileName = "dfssp_rootCA.pem" + "dfss/auth" ) // PlatformID contains platform private key and root certificate @@ -25,26 +20,29 @@ type PlatformID struct { // Initialize creates and saves the platform's private key and root certificate to a PEM format. // If ca and rKey are not nil, they will be used as the root certificate and root private key instead of creating a ones. -// The files are saved at the specified path. -func Initialize(bits, days int, country, organization, unit, cn, path string, ca *x509.Certificate, rKey *rsa.PrivateKey) error { +// The files are saved at the specified path by viper. +func Initialize(v *viper.Viper, ca *x509.Certificate, rKey *rsa.PrivateKey) error { // Generate the private key. - key, err := auth.GeneratePrivateKey(bits) + key, err := auth.GeneratePrivateKey(v.GetInt("key_size")) if err != nil { return err } var cert []byte - certPath := filepath.Join(path, RootCAFileName) - keyPath := filepath.Join(path, PkeyFileName) + path := v.GetString("path") + // ca_filename and pkey_filename are part of the global conf of + // the app, that's why we don't fetch them from the local viper + certPath := filepath.Join(path, viper.GetString("ca_filename")) + keyPath := filepath.Join(path, viper.GetString("pkey_filename")) if ca == nil { // Generate the root certificate, using the private key. - cert, err = auth.GetSelfSignedCertificate(days, auth.GenerateUID(), country, organization, unit, cn, key) + cert, err = auth.GetSelfSignedCertificate(v.GetInt("validity"), auth.GenerateUID(), v.GetString("country"), v.GetString("organization"), v.GetString("unit"), v.GetString("cn"), key) } else { - csr, _ := auth.GetCertificateRequest(country, organization, unit, cn, key) + csr, _ := auth.GetCertificateRequest(v.GetString("country"), v.GetString("organization"), v.GetString("unit"), v.GetString("cn"), key) request, _ := auth.PEMToCertificateRequest(csr) - cert, err = auth.GetCertificate(days, auth.GenerateUID(), request, ca, rKey) + cert, err = auth.GetCertificate(v.GetInt("validity"), auth.GenerateUID(), request, ca, rKey) // Override default path values certPath = filepath.Join(path, "cert.pem") keyPath = filepath.Join(path, "key.pem") @@ -77,8 +75,8 @@ func Initialize(bits, days int, country, organization, unit, cn, path string, ca // // The files are fetched using their default name. func Start(path string) (*PlatformID, error) { - keyPath := filepath.Join(path, PkeyFileName) - certPath := filepath.Join(path, RootCAFileName) + keyPath := filepath.Join(path, viper.GetString("pkey_filename")) + certPath := filepath.Join(path, viper.GetString("ca_filename")) // Recover the private rsa key from file. keyBytes, err := ioutil.ReadFile(keyPath) diff --git a/dfssp/authority/rootCA_test.go b/dfssp/authority/rootCA_test.go index f9f58be307b14f9402c5aff9cd136d76b172f4e1..b97bc871d9c64590247e383cef6ff9e29607972c 100644 --- a/dfssp/authority/rootCA_test.go +++ b/dfssp/authority/rootCA_test.go @@ -8,10 +8,22 @@ import ( "path/filepath" "testing" + "github.com/spf13/viper" + "dfss/auth" + "dfss/dfssc/common" +) + +var ( + pkey *rsa.PrivateKey + PkeyFileName = "dfssp_pkey.pem" + RootCAFileName = "dfssp_rootCA.pem" ) -var pkey *rsa.PrivateKey +func init() { + viper.Set("ca_filename", RootCAFileName) + viper.Set("pkey_filename", PkeyFileName) +} func TestMain(m *testing.M) { pkey, _ = auth.GeneratePrivateKey(512) @@ -23,7 +35,8 @@ func TestInitialize(t *testing.T) { keyPath := filepath.Join(path, PkeyFileName) certPath := filepath.Join(path, RootCAFileName) - err := Initialize(1024, 365, "country", "organization", "unit", "cn", path, nil, nil) + v := common.MockViper("key_size", 1024, "validity", 365, "country", "country", "organization", "organization", "unit", "unit", "cn", "cn", "path", path) + err := Initialize(v, nil, nil) if err != nil { t.Fatal(err) @@ -46,7 +59,8 @@ func Example() { certPath := filepath.Join(path, RootCAFileName) // Generate root certificate and key - err := Initialize(1024, 365, "UK", "DFSS", "unit", "ROOT", path, nil, nil) + v := common.MockViper("key_size", 1024, "validity", 365, "country", "UK", "organization", "DFSS", "unit", "unit", "cn", "ROOT", "path", path) + err := Initialize(v, nil, nil) if err != nil { fmt.Println(err) return @@ -64,7 +78,8 @@ func Example() { // Generate child certificate and key childPath := filepath.Join(path, "child") - err = Initialize(1024, 10, "FR", "DFSS", "unit", "CHILD", childPath, pid.RootCA, pid.Pkey) + v = common.MockViper("key_size", 1024, "validity", 10, "country", "FR", "organization", "DFSS", "unit", "unit", "cn", "CHILD", "path", childPath) + err = Initialize(v, pid.RootCA, pid.Pkey) if err != nil { fmt.Println(err) return @@ -91,7 +106,8 @@ func CheckFile(path, name string) { func TestStart(t *testing.T) { path, _ := ioutil.TempDir("", "") - _ = Initialize(1024, 365, "country", "organization", "unit", "cn", path, nil, nil) + v := common.MockViper("key_size", 1024, "validity", 365, "country", "country", "organization", "organization", "unit", "unit", "cn", "cn", "path", path) + _ = Initialize(v, nil, nil) pid, err := Start(path) if err != nil { diff --git a/dfssp/cmd/init.go b/dfssp/cmd/init.go new file mode 100644 index 0000000000000000000000000000000000000000..4d8379ff9e91ba7e8dd8aecd6ed805cee960ab80 --- /dev/null +++ b/dfssp/cmd/init.go @@ -0,0 +1,33 @@ +package cmd + +import ( + "fmt" + "os" + + "dfss/dfssc/common" + dapi "dfss/dfssd/api" + "dfss/dfssp/authority" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var initCmd = &cobra.Command{ + Use: "init", + Short: "create and save the platform's private key and root certificate", + Run: func(cmd *cobra.Command, args []string) { + + _ = viper.BindPFlag("cn", cmd.Flags().Lookup("cn")) + _ = viper.BindPFlag("validity", cmd.Flags().Lookup("validity")) + _ = viper.BindPFlag("country", cmd.Flags().Lookup("country")) + _ = viper.BindPFlag("organization", cmd.Flags().Lookup("org")) + _ = viper.BindPFlag("unit", cmd.Flags().Lookup("unit")) + _ = viper.BindPFlag("key_size", cmd.Flags().Lookup("key")) + + err := authority.Initialize(common.SubViper("key_size", "validity", "country", "organization", "unit", "cn", "path"), nil, nil) + if err != nil { + fmt.Fprintln(os.Stderr, "An error occured during the initialization operation:", err) + os.Exit(1) + } + dapi.DLog("Private key and root certificate generated") + }, +} diff --git a/dfssp/cmd/root.go b/dfssp/cmd/root.go new file mode 100644 index 0000000000000000000000000000000000000000..503f47f67d46d98f9e6428521aac52b8e434e749 --- /dev/null +++ b/dfssp/cmd/root.go @@ -0,0 +1,64 @@ +package cmd + +import ( + "dfss" + dapi "dfss/dfssd/api" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// RootCmd is the main command for the dfssp application +var RootCmd = &cobra.Command{ + Use: "dfssp", + Short: "Platform for the DFSS protocol", + Long: "Platform v " + dfss.Version + ` for the +Distributed Fair Signing System project + +Users and Contracts manager`, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + dapi.Configure(viper.GetString("demo") != "", viper.GetString("demo"), "platform") + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + dapi.DClose() + }, +} + +func init() { + // Add flags to dfssp + RootCmd.PersistentFlags().BoolP("verbose", "v", false, "print verbose messages") + RootCmd.PersistentFlags().StringP("demo", "d", "", "demonstrator address and port, let empty for no debug") + RootCmd.PersistentFlags().String("path", ".", "path to get the platform's private key and root certificate") + + initCmd.Flags().String("cn", "dfssp", "common name for the root certificate") + initCmd.Flags().IntP("validity", "r", 365, "validity duration for the root certificate (days)") + initCmd.Flags().String("country", "FR", "country for the root certificate") + initCmd.Flags().String("org", "DFSS", "organization for the root certificate") + initCmd.Flags().String("unit", "INSA Rennes", "organizational unit for the root certificate") + initCmd.Flags().IntP("key", "k", 2048, "encoding size for the private key of the platform") + + ttpCmd.Flags().String("cn", "ttp", "common name for the ttp certificate") + ttpCmd.Flags().IntP("validity", "c", 365, "validity duration for the ttp certificate (days)") + ttpCmd.Flags().String("country", "FR", "country for the ttp certificate") + ttpCmd.Flags().String("org", "DFSS", "organization for the ttp certificate") + ttpCmd.Flags().String("unit", "INSA Rennes", "organizational unit for the ttp certificate") + ttpCmd.Flags().IntP("key", "k", 2048, "encoding size for the private key of the ttp") + + startCmd.Flags().IntP("validity", "c", 365, "validity duration for the child certificates (days)") + startCmd.Flags().StringP("address", "a", "0.0.0.0", "address to bind for listening") + startCmd.Flags().StringP("port", "p", "9000", "port to bind for listening") + startCmd.Flags().String("db", "mongodb://localhost/dfss", "server url in standard MongoDB format for accessing database") + + // Bind viper to flags + _ = viper.BindPFlag("verbose", RootCmd.PersistentFlags().Lookup("verbose")) + _ = viper.BindPFlag("demo", RootCmd.PersistentFlags().Lookup("demo")) + _ = viper.BindPFlag("path", RootCmd.PersistentFlags().Lookup("path")) + + viper.SetDefault("pkey_filename", "dfssp_pkey.pem") + viper.SetDefault("ca_filename", "dfssp_rootCA.pem") + + // Register subcommands here + RootCmd.AddCommand(dfss.VersionCmd, ttpCmd, initCmd, startCmd) +} diff --git a/dfssp/cmd/start.go b/dfssp/cmd/start.go new file mode 100644 index 0000000000000000000000000000000000000000..a54709160f4b79a1d5861f0cec04b40ff16e8250 --- /dev/null +++ b/dfssp/cmd/start.go @@ -0,0 +1,36 @@ +package cmd + +import ( + "fmt" + "os" + + dapi "dfss/dfssd/api" + "dfss/dfssp/server" + "dfss/net" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var startCmd = &cobra.Command{ + Use: "start", + Short: "start the platform after loading its private key and root certificate", + Run: func(cmd *cobra.Command, args []string) { + + _ = viper.BindPFlag("dbURI", cmd.Flags().Lookup("db")) + _ = viper.BindPFlag("address", cmd.Flags().Lookup("address")) + _ = viper.BindPFlag("port", cmd.Flags().Lookup("port")) + _ = viper.BindPFlag("validity", cmd.Flags().Lookup("validity")) + + address := viper.GetString("address") + port := viper.GetString("port") + + srv := server.GetServer() + + fmt.Println("Listening on " + address + ":" + port) + dapi.DLog("Platform server started on " + address + ":" + port) + err := net.Listen(address+":"+port, srv) + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + }, +} diff --git a/dfssp/cmd/ttp.go b/dfssp/cmd/ttp.go new file mode 100644 index 0000000000000000000000000000000000000000..0e38e003b62148bda2c14892fdd5073d68a40152 --- /dev/null +++ b/dfssp/cmd/ttp.go @@ -0,0 +1,44 @@ +package cmd + +import ( + "fmt" + "os" + "path/filepath" + + "dfss/dfssc/common" + dapi "dfss/dfssd/api" + "dfss/dfssp/authority" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ttpCmd = &cobra.Command{ + Use: "ttp", + Short: "create and save the TTP's private key and certificate", + Run: func(cmd *cobra.Command, args []string) { + + _ = viper.BindPFlag("cn", cmd.Flags().Lookup("cn")) + _ = viper.BindPFlag("validity", cmd.Flags().Lookup("validity")) + _ = viper.BindPFlag("country", cmd.Flags().Lookup("country")) + _ = viper.BindPFlag("organization", cmd.Flags().Lookup("org")) + _ = viper.BindPFlag("unit", cmd.Flags().Lookup("unit")) + _ = viper.BindPFlag("key_size", cmd.Flags().Lookup("key")) + + path := viper.GetString("path") + + pid, err := authority.Start(path) + if err != nil { + fmt.Fprintln(os.Stderr, "Bad root CA or key; please use the `init` command before the `ttp` one.\n", err) + os.Exit(1) + } + ttpPath := filepath.Join(path, "ttp") + v := common.SubViper("key_size", "validity", "country", "organization", "unit", "cn") + v.Set("path", ttpPath) + err = authority.Initialize(v, pid.RootCA, pid.Pkey) + if err != nil { + fmt.Fprintln(os.Stderr, "An error occured during TTP credentials generation:", err) + os.Exit(1) + } + dapi.DLog("Private key and certificate generated for TTP") + }, +} diff --git a/dfssp/contract/contract_test.go b/dfssp/contract/contract_test.go index da5ed6495179f6fcb4459246d6f1042494b962d4..14e0dd577328c2169e10c9a06fe5a6976719981e 100644 --- a/dfssp/contract/contract_test.go +++ b/dfssp/contract/contract_test.go @@ -10,6 +10,8 @@ import ( "dfss/dfssp/server" "dfss/mgdb" "dfss/net" + + "github.com/spf13/viper" "github.com/stretchr/testify/assert" "gopkg.in/mgo.v2/bson" ) @@ -21,6 +23,8 @@ var dbURI string var repository *entities.ContractRepository func TestMain(m *testing.M) { + viper.Set("ca_filename", "dfssp_rootCA.pem") + viper.Set("pkey_filename", "dfssp_pkey.pem") dbURI = os.Getenv("DFSS_MONGO_URI") if dbURI == "" { @@ -39,8 +43,12 @@ func TestMain(m *testing.M) { // Start platform server keyPath := filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata") + viper.Set("path", keyPath) + viper.Set("dbURI", dbURI) + viper.Set("validity", 365) + viper.Set("verbose", true) - srv := server.GetServer(keyPath, dbURI, 365, true) + srv := server.GetServer() go func() { _ = net.Listen("localhost:9090", srv) }() // Run diff --git a/dfssp/main.go b/dfssp/main.go index 75bfca34362e685809b9d49eb078681a53ab04b7..eafd451574338e20b149a4cc857784fb91a346d1 100644 --- a/dfssp/main.go +++ b/dfssp/main.go @@ -1,106 +1,13 @@ package main import ( - "flag" - "fmt" "os" - "path/filepath" - "runtime" - "dfss" - dapi "dfss/dfssd/api" - "dfss/dfssp/authority" - "dfss/dfssp/server" - "dfss/net" + "dfss/dfssp/cmd" ) -var ( - verbose bool - path, country, org, unit, cn, port, address, dbURI, demo string - keySize, rootValidity, certValidity int -) - -func init() { - - flag.BoolVar(&verbose, "v", false, "Print verbose messages") - - flag.StringVar(&demo, "d", "", "Demonstrator address and port (empty string disables debug)") - flag.StringVar(&port, "p", "9000", "Default port listening") - flag.StringVar(&address, "a", "0.0.0.0", "Default address to bind for listening") - - flag.StringVar(&path, "path", ".", "Path for the platform's private key and root certificate") - flag.StringVar(&country, "country", "France", "Country for the root certificate") - flag.StringVar(&org, "org", "DFSS", "Organization for the root certificate") - flag.StringVar(&unit, "unit", "INSA Rennes", "Organizational unit for the root certificate") - flag.StringVar(&cn, "cn", "dfssp", "Common name for the root certificate") - - flag.IntVar(&keySize, "keySize", 512, "Encoding size for the private key") - flag.IntVar(&rootValidity, "rootValidity", 365, "Root certificate's validity duration (days)") - flag.IntVar(&certValidity, "certValidity", 365, "Validity duration for the certificates generated by this platform (days)") - - flag.StringVar(&dbURI, "db", "mongodb://localhost/dfss", "Name of the environment variable containing the server url in standard MongoDB format") - - flag.Usage = func() { - fmt.Println("DFSS platform v" + dfss.Version) - fmt.Println("Users and contracts manager") - - fmt.Println("\nUsage:") - fmt.Println(" dfssp [flags] command") - - fmt.Println("\nThe commands are:") - fmt.Println(" init [cn, country, keySize, org, path, unit, rootValidity]") - fmt.Println(" create and save the platform's private key and root certificate") - fmt.Println(" ttp [cn, country, keySize, org, path, unit, certValidity]") - fmt.Println(" create and save the TTP's private key and certificate") - fmt.Println(" start [path, db, a, p, certValidity]") - fmt.Println(" start the platform after loading its private key and root certificate") - fmt.Println(" help print this help") - fmt.Println(" version print dfss client version") - - fmt.Println("\nFlags:") - flag.PrintDefaults() - - fmt.Println() - } -} - func main() { - flag.Parse() - command := flag.Arg(0) - dapi.Configure(demo != "", demo, "platform") - - switch command { - case "version": - fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH) - case "init": - err := authority.Initialize(keySize, rootValidity, country, org, unit, cn, path, nil, nil) - if err != nil { - fmt.Fprintln(os.Stderr, "An error occured during the initialization operation:", err) - os.Exit(1) - } - dapi.DLog("Private key and root certificate generated") - case "ttp": - pid, err := authority.Start(path) - if err != nil { - fmt.Fprintln(os.Stderr, "Bad root CA or key; please use the `init` command before the `ttp` one.\n", err) - } - ttpPath := filepath.Join(path, "ttp") - err = authority.Initialize(keySize, certValidity, country, org, unit, cn, ttpPath, pid.RootCA, pid.Pkey) - if err != nil { - fmt.Fprintln(os.Stderr, "An error occured during TTP credentials generation:", err) - } - dapi.DLog("Private key and certificate generated for TTP") - case "start": - srv := server.GetServer(path, dbURI, certValidity, verbose) - fmt.Println("Listening on " + address + ":" + port) - dapi.DLog("Platform server started on " + address + ":" + port) - err := net.Listen(address+":"+port, srv) - if err != nil { - fmt.Fprintln(os.Stderr, err) - } - default: - flag.Usage() + if err := cmd.RootCmd.Execute(); err != nil { + os.Exit(1) } - - dapi.DClose() } diff --git a/dfssp/server/server.go b/dfssp/server/server.go index be037bfbeec3c14eddc4e49f9b4894adaf82dc19..a404576e9169b139007a0c1fac933be81131c4ed 100644 --- a/dfssp/server/server.go +++ b/dfssp/server/server.go @@ -4,6 +4,8 @@ import ( "fmt" "os" + "github.com/spf13/viper" + "dfss/dfssp/api" "dfss/dfssp/authority" "dfss/dfssp/common" @@ -11,16 +13,15 @@ import ( "dfss/dfssp/user" "dfss/mgdb" "dfss/net" + "golang.org/x/net/context" "google.golang.org/grpc" ) type platformServer struct { - Pid *authority.PlatformID - DB *mgdb.MongoManager - Rooms *common.WaitingGroupMap - CertDuration int - Verbose bool + Pid *authority.PlatformID + DB *mgdb.MongoManager + Rooms *common.WaitingGroupMap } // Register handler @@ -34,7 +35,7 @@ func (s *platformServer) Register(ctx context.Context, in *api.RegisterRequest) // // Handle incoming AuthRequest messages func (s *platformServer) Auth(ctx context.Context, in *api.AuthRequest) (*api.RegisteredUser, error) { - return user.Auth(s.Pid, s.DB, s.CertDuration, in) + return user.Auth(s.Pid, s.DB, in) } // Unregister handler @@ -98,14 +99,14 @@ func (s *platformServer) ReadySign(ctx context.Context, in *api.ReadySignRequest } // GetServer returns the GRPC server associated with the platform -func GetServer(keyPath, db string, certValidity int, verbose bool) *grpc.Server { - pid, err := authority.Start(keyPath) +func GetServer() *grpc.Server { + pid, err := authority.Start(viper.GetString("path")) if err != nil { fmt.Println("An error occured during the private key and root certificate retrieval:", err) os.Exit(1) } - dbManager, err := mgdb.NewManager(db) + dbManager, err := mgdb.NewManager(viper.GetString("dbURI")) if err != nil { fmt.Println("An error occured during the connection to MongoDB:", err) os.Exit(1) @@ -113,11 +114,9 @@ func GetServer(keyPath, db string, certValidity int, verbose bool) *grpc.Server server := net.NewServer(pid.RootCA, pid.Pkey, pid.RootCA) api.RegisterPlatformServer(server, &platformServer{ - Pid: pid, - DB: dbManager, - Rooms: common.NewWaitingGroupMap(), - CertDuration: certValidity, - Verbose: verbose, + Pid: pid, + DB: dbManager, + Rooms: common.NewWaitingGroupMap(), }) return server } diff --git a/dfssp/user/create.go b/dfssp/user/create.go index 3af4c6ecebf31f8dae8651b173aece2e366f36bf..fa844d9e2212d2259c163603871184121f263683 100644 --- a/dfssp/user/create.go +++ b/dfssp/user/create.go @@ -9,6 +9,8 @@ import ( "log" "time" + "github.com/spf13/viper" + "dfss/auth" "dfss/dfssp/api" "dfss/dfssp/authority" @@ -124,7 +126,7 @@ func Register(manager *mgdb.MongoManager, in *api.RegisterRequest) (*api.ErrorCo } // Check if the authentication request has usable fields -func checkAuthRequest(in *api.AuthRequest, certDuration int) error { +func checkAuthRequest(in *api.AuthRequest) error { if len(in.Email) == 0 { return errors.New("Invalid email length") } @@ -133,7 +135,7 @@ func checkAuthRequest(in *api.AuthRequest, certDuration int) error { return errors.New("Invalid token length") } - if certDuration < 1 { + if viper.GetInt("validity") < 1 { return errors.New("Invalid validity duration") } @@ -154,13 +156,13 @@ func checkTokenTimeout(user *entities.User) error { // Gerenate the user's certificate and certificate hash according to the specified parameters // // This function should only be called AFTER checking the AuthRequest for validity -func generateUserCert(csr string, certDuration int, parent *x509.Certificate, key *rsa.PrivateKey) ([]byte, []byte, error) { +func generateUserCert(csr string, parent *x509.Certificate, key *rsa.PrivateKey) ([]byte, []byte, error) { x509csr, err := auth.PEMToCertificateRequest([]byte(csr)) if err != nil { return nil, nil, err } - cert, err := auth.GetCertificate(certDuration, auth.GenerateUID(), x509csr, parent, key) + cert, err := auth.GetCertificate(viper.GetInt("validity"), auth.GenerateUID(), x509csr, parent, key) if err != nil { return nil, nil, err } @@ -181,9 +183,9 @@ func generateUserCert(csr string, certDuration int, parent *x509.Certificate, ke // // The user's ConnectionInfo field is NOT handled here // This data should be gathered upon beginning the signing sequence -func Auth(pid *authority.PlatformID, manager *mgdb.MongoManager, certDuration int, in *api.AuthRequest) (*api.RegisteredUser, error) { +func Auth(pid *authority.PlatformID, manager *mgdb.MongoManager, in *api.AuthRequest) (*api.RegisteredUser, error) { // Check the request validity - err := checkAuthRequest(in, certDuration) + err := checkAuthRequest(in) if err != nil { return nil, err } @@ -215,14 +217,14 @@ func Auth(pid *authority.PlatformID, manager *mgdb.MongoManager, certDuration in } // Generate the certificates and hash - cert, certHash, err := generateUserCert(user.Csr, certDuration, pid.RootCA, pid.Pkey) + cert, certHash, err := generateUserCert(user.Csr, pid.RootCA, pid.Pkey) if err != nil { return nil, err } user.Certificate = string(cert) user.CertHash = certHash - user.Expiration = time.Now().AddDate(0, 0, certDuration) + user.Expiration = time.Now().AddDate(0, 0, viper.GetInt("validity")) // Updating the database ok, err := manager.Get("users").UpdateByID(user) diff --git a/dfssp/user/user_test.go b/dfssp/user/user_test.go index 92f5b9ec2aaebdf12cb23213096a134b498a0c86..67bf74471b343b80a1cd040edcc097f665a13da0 100644 --- a/dfssp/user/user_test.go +++ b/dfssp/user/user_test.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "testing" + "time" "dfss/auth" "dfss/dfssp/api" @@ -15,10 +16,10 @@ import ( "dfss/dfssp/server" "dfss/mgdb" "dfss/net" + "github.com/spf13/viper" "github.com/stretchr/testify/assert" "golang.org/x/net/context" "gopkg.in/mgo.v2/bson" - "time" ) var ( @@ -53,6 +54,8 @@ var dbURI string var repository *entities.UserRepository func TestMain(m *testing.M) { + viper.Set("ca_filename", "dfssp_rootCA.pem") + viper.Set("pkey_filename", "dfssp_pkey.pem") dbURI = os.Getenv("DFSS_MONGO_URI") if dbURI == "" { @@ -67,13 +70,13 @@ func TestMain(m *testing.M) { keyPath := filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata") // Valid server - srv := server.GetServer(keyPath, dbURI, 365, true) + viper.Set("path", keyPath) + viper.Set("dbURI", dbURI) + viper.Set("validity", 365) + viper.Set("verbose", true) + srv := server.GetServer() go func() { _ = net.Listen(ValidServ, srv) }() - // Server using invalid certificate duration - srv2 := server.GetServer(keyPath, dbURI, -1, true) - go func() { _ = net.Listen(InvalidServ, srv2) }() - // Run err = collection.Drop() code := m.Run() diff --git a/dfsst/cmd/root.go b/dfsst/cmd/root.go new file mode 100644 index 0000000000000000000000000000000000000000..13c68f050e18d1afbf83cc1810a2deee63e86dfb --- /dev/null +++ b/dfsst/cmd/root.go @@ -0,0 +1,59 @@ +package cmd + +import ( + "fmt" + + "dfss" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// RootCmd is the main command for the dfsst application +var RootCmd = &cobra.Command{ + Use: "dfsst", + Short: "DFSS TTP v" + dfss.Version, + Long: `DFSS TTP v ` + dfss.Version + ` + +Trusted third party resolver for the +Distributed Fair Signing System project + +Sign your contract using a secure cryptographic protocol`, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, +} + +// 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 ttp's certificate") + RootCmd.PersistentFlags().String("key", "key.pem", "path to the ttp's private key") + RootCmd.PersistentFlags().StringP("demo", "d", "", "demonstrator address and port, empty will disable it") + + startCmd.Flags().StringP("address", "a", "0.0.0.0", "address to bind for listening") + startCmd.Flags().String("db", "mongodb://localhost/dfss", "server url in standard MongoDB format to access the database") + startCmd.Flags().IntP("port", "p", 9020, "port to bind for listening") + + // 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("port", startCmd.Flags().Lookup("port")) + _ = viper.BindPFlag("address", startCmd.Flags().Lookup("address")) + _ = viper.BindPFlag("dbURI", startCmd.Flags().Lookup("db")) + + if err := viper.BindEnv("password", "DFSS_TTP_PASSWORD"); err != nil { + fmt.Println("Warning: The DFSS_TTP_PASSWORD environment variable is not set, assuming the private key is decrypted") + viper.Set("password", "") + } + + // Register Sub Commands + RootCmd.AddCommand(dfss.VersionCmd, startCmd) + +} diff --git a/dfsst/cmd/start.go b/dfsst/cmd/start.go new file mode 100644 index 0000000000000000000000000000000000000000..c36cab923075b22996cedf8fbad9b78b1cc31cc0 --- /dev/null +++ b/dfsst/cmd/start.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "fmt" + "os" + "strconv" + + dapi "dfss/dfssd/api" + "dfss/dfsst/server" + "dfss/net" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// startCmd represents the start command +var startCmd = &cobra.Command{ + Use: "start", + Short: "Start the TTP service", + Long: `Start the TTP of the DFSS project + +Fill the DFSS_TTP_PASSWORD environment variable if the private key is enciphered`, + Run: func(cmd *cobra.Command, args []string) { + demo := viper.GetString("demo") + dapi.Configure(demo != "", demo, "ttp") + + srv := server.GetServer() + + addrPort := viper.GetString("address") + ":" + strconv.Itoa(viper.GetInt("port")) + fmt.Println("Listening on " + addrPort) + dapi.DLog("TTP server started on " + addrPort) + err := net.Listen(addrPort, srv) + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + + dapi.DClose() + }, +} diff --git a/dfsst/entities/archivesManager.go b/dfsst/entities/archivesManager.go index 1a6205f59d853b20a9aeae721e7160461adc1a66..527f7cba932bf273db8e8c97a788a7dfa33b41d1 100644 --- a/dfsst/entities/archivesManager.go +++ b/dfsst/entities/archivesManager.go @@ -3,6 +3,7 @@ package entities import ( cAPI "dfss/dfssc/api" "dfss/mgdb" + "gopkg.in/mgo.v2/bson" ) @@ -112,7 +113,7 @@ func (manager *ArchivesManager) AddToDishonest(signerIndex uint32) { // AddPromise : adds the specified promises to the list of received promises of the SignatureArchives. func (manager *ArchivesManager) AddPromise(promise *Promise) { for _, p := range manager.Archives.ReceivedPromises { - if ArePromisesEqual(&p, promise) { + if (&p).Equal(promise) { return } } diff --git a/dfsst/entities/signatureArchives.go b/dfsst/entities/signatureArchives.go index 31ea2a5465e4667ab021d6902e32049c868028d4..1f34fcbf97f43187f9257f0c08057756ee3296ab 100644 --- a/dfsst/entities/signatureArchives.go +++ b/dfsst/entities/signatureArchives.go @@ -75,9 +75,9 @@ func NewPromise(recipientIndex, senderIndex, sequenceIndex uint32) *Promise { } } -// ArePromisesEqual : determines if the two specified promises share the same information, without considering the +// Equal : determines if the two specified promises share the same information, without considering the // bson object id. -func ArePromisesEqual(p1, p2 *Promise) bool { +func (p1 *Promise) Equal(p2 *Promise) bool { if p1.RecipientKeyIndex != p2.RecipientKeyIndex { return false } diff --git a/dfsst/entities/signatureArchives_test.go b/dfsst/entities/signatureArchives_test.go index 836a263fbfda86445115b42a96e3b633b587e788..ce42e1f598ad172b7f2771081901532922e268b9 100644 --- a/dfsst/entities/signatureArchives_test.go +++ b/dfsst/entities/signatureArchives_test.go @@ -10,18 +10,18 @@ func TestArePromisesEqual(t *testing.T) { promise0 := NewPromise(uint32(1), uint32(0), uint32(0)) promise1 := NewPromise(uint32(0), uint32(1), uint32(1)) - equal := ArePromisesEqual(promise0, promise1) + equal := promise0.Equal(promise1) assert.Equal(t, equal, false) promise1.RecipientKeyIndex = uint32(1) - equal = ArePromisesEqual(promise0, promise1) + equal = promise0.Equal(promise1) assert.Equal(t, equal, false) promise1.SenderKeyIndex = uint32(0) - equal = ArePromisesEqual(promise0, promise1) + equal = promise0.Equal(promise1) assert.Equal(t, equal, false) promise1.SequenceIndex = uint32(0) - equal = ArePromisesEqual(promise0, promise1) + equal = promise0.Equal(promise1) assert.Equal(t, equal, true) } diff --git a/dfsst/main.go b/dfsst/main.go index ee3b6a94f62e7b704bd1fcf222da22ffb4fcaca8..a84f4a4441ed86546a63faa3ff65583476d2321c 100644 --- a/dfsst/main.go +++ b/dfsst/main.go @@ -1,83 +1,13 @@ package main import ( - "flag" - "fmt" "os" - "runtime" - "dfss" - dapi "dfss/dfssd/api" - "dfss/dfsst/server" - "dfss/net" + "dfss/dfsst/cmd" ) -var ( - verbose bool - fca string // Path to the CA - fcert string // Path to the certificate - fkey string // Path to the private key - address string - dbURI string - port string - demo string -) - -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(&demo, "d", "", "Demonstrator address and port (empty string disables debug)") - - flag.StringVar(&port, "p", "9020", "Default port listening") - flag.StringVar(&address, "a", "0.0.0.0", "Default address to bind for listening") - - flag.StringVar(&dbURI, "db", "mongodb://localhost/dfss", "Name of the environment variable containing the server url in standard MongoDB format") - - flag.Usage = func() { - fmt.Println("DFSS TTP v" + dfss.Version) - fmt.Println("Trusted third party resolver") - - fmt.Println("\nUsage:") - fmt.Println(" dfssp [flags] command") - - fmt.Println("\nThe commands are:") - fmt.Println(" start start the TTP service") - fmt.Println(" fill the `DFSS_TTP_PASSWORD` environment variable if the private key is enciphered") - fmt.Println(" help print this help") - fmt.Println(" version print dfss protocol version") - - fmt.Println("\nFlags:") - flag.PrintDefaults() - - fmt.Println() - } -} - func main() { - flag.Parse() - command := flag.Arg(0) - dapi.Configure(demo != "", demo, "ttp") - - switch command { - case "version": - fmt.Println("v"+dfss.Version, runtime.GOOS, runtime.GOARCH) - case "start": - password := os.Getenv("DFSS_TTP_PASSWORD") - srv := server.GetServer(fca, fcert, fkey, password, dbURI, verbose) - - addrPort := address + ":" + port - fmt.Println("Listening on " + addrPort) - dapi.DLog("TTP server started on " + addrPort) - err := net.Listen(addrPort, srv) - if err != nil { - fmt.Fprintln(os.Stderr, err) - } - default: - flag.Usage() + if err := cmd.RootCmd.Execute(); err != nil { + os.Exit(1) } - - dapi.DClose() } diff --git a/dfsst/resolve/resolve.go b/dfsst/resolve/resolve.go index 9ca93efc963fdceb07058a15927bc40c7380ef21..369d423565f19b059a0feff154fd75db4ded18a3 100644 --- a/dfsst/resolve/resolve.go +++ b/dfsst/resolve/resolve.go @@ -30,7 +30,7 @@ func Solve(manager *entities.ArchivesManager) (bool, []byte) { // GenerateSignedContract : generates the signed contract. // Does not take into account if we have the evidence to do it (see function 'CanGenerate'). // -// IMPLEMENTATION REQUIRES THE IMPLEMENTATION OF PROMISES. +// XXX : Implementation needs cryptographic promises func GenerateSignedContract(archives *entities.SignatureArchives) []byte { // TODO return []byte{0, 0, 7} diff --git a/dfsst/server/server.go b/dfsst/server/server.go index d82a5a34e1b19e1174d486b2ad7722841cc8b8ed..63e5dc1a1411d0bed93d8540c61ebc25fa8b6aa9 100644 --- a/dfsst/server/server.go +++ b/dfsst/server/server.go @@ -12,6 +12,8 @@ import ( "dfss/dfsst/resolve" "dfss/mgdb" "dfss/net" + + "github.com/spf13/viper" "golang.org/x/net/context" "google.golang.org/grpc" ) @@ -20,8 +22,7 @@ import ( const InternalError string = "Internal server error" type ttpServer struct { - DB *mgdb.MongoManager - Verbose bool + DB *mgdb.MongoManager } // Alert route for the TTP. @@ -177,23 +178,23 @@ func (server *ttpServer) Recover(ctx context.Context, in *tAPI.RecoverRequest) ( } // GetServer returns the gRPC server. -func GetServer(fca, fcert, fkey, password, db string, verbose bool) *grpc.Server { - auth := security.NewAuthContainer(fca, fcert, fkey, "", password) +func GetServer() *grpc.Server { + // We can do that because NewAuthContainer is looking for "file_ca", "file_cert", and "file_key" in viper, which are set by the TTP + auth := security.NewAuthContainer(viper.GetString("password")) ca, cert, key, err := auth.LoadFiles() if err != nil { fmt.Fprintln(os.Stderr, "An error occured during the private key and certificates retrieval:", err) os.Exit(1) } - dbManager, err := mgdb.NewManager(db) + dbManager, err := mgdb.NewManager(viper.GetString("dbURI")) if err != nil { fmt.Fprintln(os.Stderr, "An error occured during the connection to MongoDB:", err) os.Exit(2) } server := &ttpServer{ - Verbose: verbose, - DB: dbManager, + DB: dbManager, } netServer := net.NewServer(cert, key, ca) tAPI.RegisterTTPServer(netServer, server) diff --git a/dfsst/server/server_test.go b/dfsst/server/server_test.go index f3c1275be359d44ed3f6000312c680524d821d93..4d3dad9ad9d09cff788883a695fae5b05558d23f 100644 --- a/dfsst/server/server_test.go +++ b/dfsst/server/server_test.go @@ -10,9 +10,12 @@ import ( "path/filepath" "testing" + "github.com/spf13/viper" + "dfss/auth" "dfss/dfsst/entities" "dfss/mgdb" + "gopkg.in/mgo.v2/bson" ) @@ -91,9 +94,9 @@ func TestMain(m *testing.M) { os.Exit(2) } + viper.Set("verbose", true) ttp = &ttpServer{ - Verbose: true, - DB: dbManager, + DB: dbManager, } code := m.Run() diff --git a/gui/authform/authform.go b/gui/authform/authform.go index 8a0445a41d8e411c88bb938b0e52e0036f7eeec4..cda58f59be1bd9169a970c97c21f6deaa5bdcb0c 100644 --- a/gui/authform/authform.go +++ b/gui/authform/authform.go @@ -2,7 +2,8 @@ package authform import ( "dfss/dfssc/user" - "dfss/gui/config" + + "github.com/spf13/viper" "github.com/visualfc/goqt/ui" ) @@ -10,7 +11,7 @@ type Widget struct { *ui.QWidget } -func NewWidget(conf *config.Config, onAuth func()) *Widget { +func NewWidget(onAuth func()) *Widget { file := ui.NewFileWithName(":/authform/authform.ui") loader := ui.NewUiLoader() form := loader.Load(file) @@ -19,14 +20,10 @@ func NewWidget(conf *config.Config, onAuth func()) *Widget { feedbackLabel := ui.NewLabelFromDriver(form.FindChild("feedbackLabel")) authButton := ui.NewPushButtonFromDriver(form.FindChild("authButton")) - home := config.GetHomeDir() authButton.OnClicked(func() { form.SetDisabled(true) err := user.Authenticate( - home+config.CAFile, - home+config.CertFile, - conf.Platform, - conf.Email, + viper.GetString("email"), tokenField.Text(), ) form.SetDisabled(false) diff --git a/gui/config/config.go b/gui/config/config.go index 1b99d66af0cae8169582a470aec19d19470061b8..015c39d57aba575a976bbcd02bbcc36e226e70c2 100644 --- a/gui/config/config.go +++ b/gui/config/config.go @@ -8,55 +8,51 @@ import ( "os" "os/user" "path/filepath" -) - -// CAFile is the filename for the root certificate -const CAFile = "ca.pem" - -// CertFile is the filename for the user certificate -const CertFile = "cert.pem" - -// KeyFile is the filename for the private user key -const KeyFile = "key.pem" -// ConfigFile is the filename for the DFSS configuration file -const ConfigFile = "config.json" + "github.com/spf13/viper" +) // Config is the structure that will be persisted in the configuration file type Config struct { - Email string - Platform string - - // Virtual-only fields - Registered bool `json:"-"` - Authenticated bool `json:"-"` + Email string `json: email` + Platform string `json: platform` } // Load loads the configuration file into memory. // If the file does not exist, the configuration will holds default values. -func Load() (conf Config) { - data, err := ioutil.ReadFile(getConfigFilename()) - if err != nil { - return - } +func Load() { + // Load config file + path := GetHomeDir() + viper.AddConfigPath(GetHomeDir()) + viper.SetConfigName(viper.GetString("filename_config")) + viper.ReadInConfig() - _ = json.Unmarshal(data, &conf) + // Alias for platform + viper.RegisterAlias("platform_addrport", "platform") + + // Setup file paths + viper.Set("home_dir", path) + viper.Set("file_ca", filepath.Join(path, viper.GetString("filename_ca"))) + viper.Set("file_cert", filepath.Join(path, viper.GetString("filename_cert"))) + viper.Set("file_key", filepath.Join(path, viper.GetString("filename_key"))) + viper.Set("file_config", filepath.Join(path, viper.GetString("filename_config")) + ".json") // Fill virtual-only fields - path := GetHomeDir() - conf.Registered = isFileValid(filepath.Join(path, KeyFile)) - conf.Authenticated = isFileValid(filepath.Join(path, CertFile)) + viper.Set("registered", isFileValid(viper.GetString("file_key"))) + viper.Set("authenticated", isFileValid(viper.GetString("file_cert"))) + return } // Save stores the current configuration object from memory. -func Save(c Config) { +func Save() { + c := Config{viper.GetString("email"), viper.GetString("platform")} data, err := json.MarshalIndent(c, "", " ") if err != nil { return } - _ = ioutil.WriteFile(getConfigFilename(), data, 0600) + _ = ioutil.WriteFile(viper.GetString("file_config"), data, 0600) } // GetHomeDir is a helper to get the .dfss store directory @@ -74,10 +70,6 @@ func GetHomeDir() string { return dfssPath + string(filepath.Separator) } -func getConfigFilename() string { - return filepath.Join(GetHomeDir(), ConfigFile) -} - func isFileValid(file string) bool { _, err := os.Stat(file) return err == nil diff --git a/gui/config/pwddialog.go b/gui/config/pwddialog.go index 7ef882e8f97ff5d1e627691c80ff37c02d3a6d65..258a1f6eb602a7c5f0d03ec0c3b775ec5a754fb3 100644 --- a/gui/config/pwddialog.go +++ b/gui/config/pwddialog.go @@ -5,6 +5,8 @@ import ( "io/ioutil" "dfss/auth" + + "github.com/spf13/viper" "github.com/visualfc/goqt/ui" ) @@ -15,8 +17,7 @@ import ( // The callback is always called, even when an error occurs. func PasswordDialog(callback func(err error, pwd string)) { // Try to get private key - path := GetHomeDir() + KeyFile - data, err := ioutil.ReadFile(path) + data, err := ioutil.ReadFile(viper.GetString("file_key")) if err != nil { callback(err, "") return diff --git a/gui/contractform/contractform.go b/gui/contractform/contractform.go index 9cd9ec371d5c9d14929e6ad99494104c2f9f128d..ee284cc412f3a45981ffadba967376a8041f39d6 100644 --- a/gui/contractform/contractform.go +++ b/gui/contractform/contractform.go @@ -5,6 +5,8 @@ import ( "dfss/dfssc/sign" "dfss/gui/config" + + "github.com/spf13/viper" "github.com/visualfc/goqt/ui" ) @@ -14,7 +16,7 @@ type Widget struct { signers *ui.QPlainTextEdit } -func NewWidget(conf *config.Config) *Widget { +func NewWidget() *Widget { file := ui.NewFileWithName(":/contractform/contractform.ui") loader := ui.NewUiLoader() form := loader.Load(file) @@ -31,7 +33,7 @@ func NewWidget(conf *config.Config) *Widget { signers: signersField, } - signersField.SetPlainText(conf.Email + "\n") + signersField.SetPlainText(viper.GetString("email") + "\n") fileButton.OnClicked(func() { filter := "Any (*.*)" @@ -49,12 +51,7 @@ func NewWidget(conf *config.Config) *Widget { return // wrong key or rejection, aborting } - home := config.GetHomeDir() err = sign.SendNewContract( - home+config.CAFile, - home+config.CertFile, - home+config.KeyFile, - conf.Platform, pwd, fileField.Text(), commentField.ToPlainText(), diff --git a/gui/main.go b/gui/main.go index 24fe004d62a6dda74aeaefc46549182a0d0d7368..567958731922a47b78cff2693613afe6364589e9 100644 --- a/gui/main.go +++ b/gui/main.go @@ -7,6 +7,7 @@ import ( "dfss/gui/contractform" "dfss/gui/signform" "dfss/gui/userform" + "github.com/spf13/viper" "github.com/visualfc/goqt/ui" ) @@ -14,7 +15,6 @@ type window struct { *ui.QMainWindow current widget - conf *config.Config } type widget interface { @@ -22,21 +22,27 @@ type widget interface { Tick() } +func init() { + viper.Set("filename_ca", "ca.pem") + viper.Set("filename_cert", "cert.pem") + viper.Set("filename_key", "key.pem") + viper.Set("filename_config", "config") +} + func main() { // Load configuration - conf := config.Load() + config.Load() // Start first window ui.Run(func() { w := &window{ QMainWindow: ui.NewMainWindow(), - conf: &conf, } - if conf.Authenticated { + if viper.GetBool("authenticated") { w.addActions() w.showNewContractForm() - } else if conf.Registered { + } else if viper.GetBool("registered") { w.showAuthForm() } else { w.showUserForm() @@ -73,29 +79,29 @@ func (w *window) setScreen(wi widget) { } func (w *window) showUserForm() { - w.setScreen(userform.NewWidget(w.conf, func(pwd string) { + w.setScreen(userform.NewWidget(func(pwd string) { w.showAuthForm() })) } func (w *window) showAuthForm() { - w.setScreen(authform.NewWidget(w.conf, func() { + w.setScreen(authform.NewWidget(func() { w.showNewContractForm() w.addActions() })) } func (w *window) showNewContractForm() { - w.setScreen(contractform.NewWidget(w.conf)) + w.setScreen(contractform.NewWidget()) } func (w *window) showSignForm() { - home := config.GetHomeDir() + home := viper.GetString("home_dir") filter := "Contract file (*.json);;Any (*.*)" filename := ui.QFileDialogGetOpenFileNameWithParentCaptionDirFilterSelectedfilterOptions(w, "Select the contract file", home, filter, &filter, 0) if filename != "" { config.PasswordDialog(func(err error, pwd string) { - widget := signform.NewWidget(w.conf, filename, pwd) + widget := signform.NewWidget(filename, pwd) if widget != nil { w.setScreen(widget) } diff --git a/gui/signform/signform.go b/gui/signform/signform.go index 311738e8943f056ff4d93dd85594a6ef03b220e1..b8629cf7d4cf37ca76219106644242086a7d5c7b 100644 --- a/gui/signform/signform.go +++ b/gui/signform/signform.go @@ -6,7 +6,7 @@ import ( "dfss/dfssc/sign" "dfss/dfssp/contract" - "dfss/gui/config" + "github.com/spf13/viper" "github.com/visualfc/goqt/ui" ) @@ -29,7 +29,7 @@ type Widget struct { feedback string } -func NewWidget(conf *config.Config, filename, pwd string) *Widget { +func NewWidget(filename, pwd string) *Widget { loadIcons() file := ui.NewFileWithName(":/signform/signform.ui") loader := ui.NewUiLoader() @@ -51,14 +51,8 @@ func NewWidget(conf *config.Config, filename, pwd string) *Widget { return nil } - home := config.GetHomeDir() m, err := sign.NewSignatureManager( - home+config.CAFile, - home+config.CertFile, - home+config.KeyFile, - conf.Platform, pwd, - 9005, // TODO change port w.contract, ) if err != nil { @@ -73,7 +67,7 @@ func NewWidget(conf *config.Config, filename, pwd string) *Widget { } w.initLines() - w.signerUpdated(conf.Email, sign.StatusConnected, "It's you!") + w.signerUpdated(viper.GetString("email"), sign.StatusConnected, "It's you!") go func() { err = w.execute() if err != nil { diff --git a/gui/userform/userform.go b/gui/userform/userform.go index 8f424e77bcd974c4c7f1428118cfecbfa703bc0d..30f234f9d804f89727fd728b5b4ed8d21fa82654 100644 --- a/gui/userform/userform.go +++ b/gui/userform/userform.go @@ -5,6 +5,8 @@ import ( "dfss/dfssc/user" "dfss/gui/config" + + "github.com/spf13/viper" "github.com/visualfc/goqt/ui" ) @@ -12,7 +14,7 @@ type Widget struct { *ui.QWidget } -func NewWidget(conf *config.Config, onRegistered func(pw string)) *Widget { +func NewWidget(onRegistered func(pw string)) *Widget { file := ui.NewFileWithName(":/userform/userform.ui") loader := ui.NewUiLoader() form := loader.Load(file) @@ -25,7 +27,7 @@ func NewWidget(conf *config.Config, onRegistered func(pw string)) *Widget { feedbackLabel := ui.NewLabelFromDriver(form.FindChild("feedbackLabel")) registerButton := ui.NewPushButtonFromDriver(form.FindChild("registerButton")) - home := config.GetHomeDir() + home := viper.GetString("home_dir") // Events @@ -34,24 +36,19 @@ func NewWidget(conf *config.Config, onRegistered func(pw string)) *Widget { feedbackLabel.SetText("Registration in progress...") filter := "Root Certificates (*.pem);;Any (*.*)" caFilename := ui.QFileDialogGetOpenFileNameWithParentCaptionDirFilterSelectedfilterOptions(form, "Select the CA file for the platform", home, filter, &filter, 0) - caDest := home + config.CAFile - _ = copyCA(caFilename, caDest) + _ = copyCA(caFilename) + viper.Set("platform_addrport", hostField.Text()) err := user.Register( - caDest, - home+config.CertFile, - home+config.KeyFile, - hostField.Text(), passwordField.Text(), "", "", "", emailField.Text(), 2048, ) if err != nil { feedbackLabel.SetText(err.Error()) } else { - conf.Email = emailField.Text() - conf.Platform = hostField.Text() + viper.Set("email", emailField.Text()) onRegistered(passwordField.Text()) - config.Save(*conf) + config.Save() } form.SetDisabled(false) }) @@ -59,8 +56,8 @@ func NewWidget(conf *config.Config, onRegistered func(pw string)) *Widget { return &Widget{QWidget: form} } -func copyCA(from string, to string) error { - if from == to { +func copyCA(from string) error { + if from == viper.GetString("file_ca") { return nil } @@ -69,7 +66,7 @@ func copyCA(from string, to string) error { return err } - return ioutil.WriteFile(to, file, 0600) + return ioutil.WriteFile(viper.GetString("file_ca"), file, 0600) } func (w *Widget) Q() *ui.QWidget { diff --git a/tests/impexp_test.go b/tests/impexp_test.go index 872fd609dd47aead56435867d27a82640bccdf44..ed268b6e4f27d6f8fc22726da986beee186c5c65 100644 --- a/tests/impexp_test.go +++ b/tests/impexp_test.go @@ -40,7 +40,7 @@ func TestExport(t *testing.T) { path := filepath.Join(os.Getenv("GOPATH"), "bin", "dfssc") // Basic command - cmd := exec.Command(path, "-cert", certPath, "-key", keyPath, "export", confPath) + cmd := exec.Command(path, "--cert", certPath, "--key", keyPath, "export", confPath) // Export the configuration cmd.Stdin = strings.NewReader( @@ -52,7 +52,7 @@ func TestExport(t *testing.T) { assert.True(t, common.FileExists(confPath)) // Bad case 1 : Wrong passphrase for private key - badCmd1 := exec.Command(path, "-cert", certPath, "-key", keyPath, "export", confPath) + badCmd1 := exec.Command(path, "--cert", certPath, "--key", keyPath, "export", confPath) common.DeleteQuietly(confPath) badCmd1.Stdin = strings.NewReader( "passphrase\n" + @@ -63,7 +63,7 @@ func TestExport(t *testing.T) { assert.True(t, !common.FileExists(confPath)) // Bad case 2 : Missing certificate - badCmd2 := exec.Command(path, "-cert", certPath, "-key", keyPath, "export", confPath) + badCmd2 := exec.Command(path, "--cert", certPath, "--key", keyPath, "export", confPath) common.DeleteQuietly(certPath) badCmd2.Stdin = strings.NewReader( "passphrase\n" + @@ -104,7 +104,7 @@ func TestImport(t *testing.T) { path := filepath.Join(os.Getenv("GOPATH"), "bin", "dfssc") // Create the config file - cmd := exec.Command(path, "-cert", certPath, "-key", keyPath, "export", confPath) + cmd := exec.Command(path, "--cert", certPath, "--key", keyPath, "export", confPath) cmd.Stdin = strings.NewReader( "pass\n" + diff --git a/tests/new_test.go b/tests/new_test.go index 2c8c8682dc31189076dc63ef038a9bfa22bb980b..14530f1cb43f8c65aa9ac10553df120fa9b40d10 100644 --- a/tests/new_test.go +++ b/tests/new_test.go @@ -39,6 +39,7 @@ func TestNewContract(t *testing.T) { // Register client1 client1, err := createClient(workingDir, ca, 0) assert.Equal(t, nil, err) + err = registerAndAuth(client1, "client1@example.com", "password", "", true, true) assert.Equal(t, nil, err) diff --git a/tests/starters_test.go b/tests/starters_test.go index b219fd8483580f904b107d3445ee5b273786dbd4..f7f8f8ff573f4e26364ee598ce1053916bbbbdf9 100644 --- a/tests/starters_test.go +++ b/tests/starters_test.go @@ -30,14 +30,14 @@ func startPlatform(tmpDir string) (platform, ttp, demo *exec.Cmd, stop func(), c } // Init - cmd := exec.Command(path, "-path", dir, "-v", "init") + cmd := exec.Command(path, "--path", dir, "-v", "init") err = cmd.Run() if err != nil { return } // Create TTP working directory - cmd = exec.Command(path, "-path", dir, "-v", "-cn", "ttp", "ttp") + cmd = exec.Command(path, "--path", dir, "-v", "--cn", "ttp", "ttp") err = cmd.Run() if err != nil { return @@ -50,13 +50,13 @@ func startPlatform(tmpDir string) (platform, ttp, demo *exec.Cmd, stop func(), c } // Start platform - platform = exec.Command(path, "-db", dbURI, "-path", dir, "-p", testPort, "-v", "start") + platform = exec.Command(path, "--db", dbURI, "--path", dir, "-p", testPort, "-v", "start") platform.Stdout = os.Stdout platform.Stderr = os.Stderr err = platform.Start() // Start TTP - ttp = exec.Command(ttpPath, "-db", dbURI, "-p", "9098", "start") + ttp = exec.Command(ttpPath, "--db", dbURI, "--port", "9098", "start") ttp.Dir = filepath.Join(dir, "ttp") ttp.Stdout = os.Stdout ttp.Stderr = os.Stderr @@ -64,7 +64,7 @@ func startPlatform(tmpDir string) (platform, ttp, demo *exec.Cmd, stop func(), c err = ttp.Start() // Start demonstrator - demo = exec.Command(demoPath, "-p", "9099", "nogui") + demo = exec.Command(demoPath, "--port", "9099", "nogui") demo.Stdout = os.Stdout demo.Stderr = os.Stderr err = demo.Start() @@ -105,7 +105,7 @@ func createClient(tmpDir string, ca []byte, port int) (*exec.Cmd, error) { // Prepare the client command. // The last argument is up to you! - cmd := exec.Command(path, "-ca", caPath, "-cert", certPath, "-host", "127.0.0.1:"+testPort, "-key", keyPath, "-port", strconv.Itoa(port), "-v", "-d", "localhost:9099") + cmd := exec.Command(path, "--ca", caPath, "--cert", certPath, "--host", "127.0.0.1:"+testPort, "--key", keyPath, "--port", strconv.Itoa(port), "-v", "-d", "localhost:9099") return cmd, nil } diff --git a/version.go b/version.go index 1056631ad1aa87a0d92a5e8aaee123700f9823a5..45ff4031fcb9d4dd6f01022812b62b99691db720 100644 --- a/version.go +++ b/version.go @@ -1,4 +1,20 @@ package dfss +import ( + "fmt" + "runtime" + + "github.com/spf13/cobra" +) + // Version represents the current version of the DFSS software suite const Version = "0.2.0-dev" + +// VersionCmd is the cobra command common to all dfss modules +var VersionCmd = &cobra.Command{ + Use: "version", + Short: "print version of dfss protocol", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("DFSS v"+Version, runtime.GOOS, runtime.GOARCH) + }, +}