Exemplo n.º 1
0
func kvDel(c *cli.Context) error {
	cfg := loadConfigOrFail(c)
	if c.NArg() != 1 {
		log.Fatal("Please give a key to delete")
	}
	key := c.Args().First()
	prop := cfg.GetProposed()
	if _, ok := prop.Data[key]; !ok {
		log.Fatal("Didn't find key", key, "in the config")
	}
	delete(prop.Data, key)
	log.ErrFatal(cfg.ProposeSend(prop))
	return cfg.saveConfig(c)
}
Exemplo n.º 2
0
func newIdentityService(c *onet.Context, path string) onet.Service {
	s := &Service{
		ServiceProcessor: onet.NewServiceProcessor(c),
		StorageMap:       &StorageMap{make(map[string]*Storage)},
		skipchain:        skipchain.NewClient(),
		path:             path,
	}
	var err error
	s.propagateIdentity, err =
		manage.NewPropagationFunc(c, "IdentityPropagateID", s.propagateIdentityHandler)
	if err != nil {
		return nil
	}
	s.propagateSkipBlock, err =
		manage.NewPropagationFunc(c, "IdentityPropagateSB", s.propagateSkipBlockHandler)
	if err != nil {
		return nil
	}
	s.propagateConfig, err =
		manage.NewPropagationFunc(c, "IdentityPropagateConf", s.propagateConfigHandler)
	if err != nil {
		return nil
	}
	if err := s.tryLoad(); err != nil {
		log.Error(err)
	}
	for _, f := range []interface{}{s.ProposeSend, s.ProposeVote,
		s.CreateIdentity, s.ProposeUpdate, s.ConfigUpdate} {
		if err := s.RegisterHandler(f); err != nil {
			log.Fatal("Registration error:", err)
		}
	}
	return s
}
Exemplo n.º 3
0
func followAdd(c *cli.Context) error {
	if c.NArg() < 2 {
		log.Fatal("Please give a group-definition, an ID, and optionally a service-name of the skipchain to follow")
	}
	cfg, _ := loadConfig(c)
	group := getGroup(c)
	idBytes, err := hex.DecodeString(c.Args().Get(1))
	log.ErrFatal(err)
	id := identity.ID(idBytes)
	newID, err := identity.NewIdentityFromCothority(group.Roster, id)
	log.ErrFatal(err)
	if c.NArg() == 3 {
		newID.DeviceName = c.Args().Get(2)
	} else {
		var err error
		newID.DeviceName, err = os.Hostname()
		log.ErrFatal(err)
		log.Info("Using", newID.DeviceName, "as the device-name.")
	}
	cfg.Follow = append(cfg.Follow, newID)
	cfg.writeAuthorizedKeys(c)
	// Identity needs to exist, else saving/loading will fail. For
	// followers it doesn't matter if the identity will be overwritten,
	// as it is not used.
	cfg.Identity = newID
	return cfg.saveConfig(c)
}
Exemplo n.º 4
0
func (sr *BlockReply) UnmarshalJSON(dataJSON []byte) error {
	type Alias BlockReply
	//log.Print("Starting unmarshal")
	suite, err := suites.StringToSuite(sr.SuiteStr)
	if err != nil {
		return err
	}
	aux := &struct {
		SignatureInfo []byte
		Response      abstract.Scalar
		Challenge     abstract.Scalar
		AggCommit     abstract.Point
		AggPublic     abstract.Point
		*Alias
	}{
		Response:  suite.Scalar(),
		Challenge: suite.Scalar(),
		AggCommit: suite.Point(),
		AggPublic: suite.Point(),
		Alias:     (*Alias)(sr),
	}
	//log.Print("Doing JSON unmarshal")
	if err := json.Unmarshal(dataJSON, &aux); err != nil {
		return err
	}
	if err := suite.Read(bytes.NewReader(aux.SignatureInfo), &sr.Response, &sr.Challenge, &sr.AggCommit, &sr.AggPublic); err != nil {
		log.Fatal("decoding signature Response / Challenge / AggCommit: ", err)
		return err
	}
	return nil
}
Exemplo n.º 5
0
// Gets the block-directory starting from the current directory - this will
// hold up when running it with 'simul'
func GetBlockDir() string {
	dir, err := os.Getwd()
	if err != nil {
		log.Fatal("Couldn't get working dir:", err)
	}
	return dir + "/blocks"
}
Exemplo n.º 6
0
// loadConfig will try to load the configuration and `fatal` if it is there but
// not valid. If the config-file is missing altogether, loaded will be false and
// an empty config-file will be returned.
func loadConfig(c *cli.Context) (cfg *ciscConfig, loaded bool) {
	cfg = &ciscConfig{Identity: &identity.Identity{}}
	loaded = true

	configFile := getConfig(c)
	log.Lvl2("Loading from", configFile)
	buf, err := ioutil.ReadFile(configFile)
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		log.ErrFatal(err)
	}
	_, msg, err := network.UnmarshalRegistered(buf)
	log.ErrFatal(err)
	cfg, loaded = msg.(*ciscConfig)
	cfg.Identity.Client = onet.NewClient(identity.ServiceName)
	for _, f := range cfg.Follow {
		f.Client = onet.NewClient(identity.ServiceName)
	}
	if !loaded {
		log.Fatal("Wrong message-type in config-file")
	}
	return
}
Exemplo n.º 7
0
// signFile will search for the file and sign it
// it always returns nil as an error
func signFile(c *cli.Context) error {
	if c.Args().First() == "" {
		log.Fatal("Please give the file to sign", 1)
	}
	fileName := c.Args().First()
	groupToml := c.String(optionGroup)
	file, err := os.Open(fileName)
	log.ErrFatal(err, "Couldn't read file to be signed:")

	sig, err := sign(file, groupToml)
	log.ErrFatal(err, "Couldn't create signature:")

	log.Lvl3(sig)
	var outFile *os.File
	outFileName := c.String("out")
	if outFileName != "" {
		outFile, err = os.Create(outFileName)
		log.ErrFatal(err, "Couldn't create signature file:")
	} else {
		outFile = os.Stdout
	}
	writeSigAsJSON(sig, outFile)
	if outFileName != "" {
		log.Lvl2("Signature written to: %s", outFile.Name())
	} // else keep the Stdout empty
	return nil
}
Exemplo n.º 8
0
func main() {
	network.RegisterPacketType(&Database{})

	app := cli.NewApp()
	app.Name = "Guard"
	app.Usage = "Get and print status of all servers of a file."

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "group, gd",
			Value: "group.toml",
			Usage: "Cothority group definition in `FILE.toml`",
		},
		cli.IntFlag{
			Name:  "debug, d",
			Value: 0,
			Usage: "debug-level: `integer`: 1 for terse, 5 for maximal",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:    "setpass",
			Aliases: []string{"s"},
			Usage:   "Setup the configuration for the server (interactive)",
			Action:  setpass,
		},
		{
			Name:      "setup",
			Aliases:   []string{"su"},
			Usage:     "Saves the cothority group-toml to the configuration",
			ArgsUsage: "Give group definition",
			Action:    setup,
		},
		{
			Name:    "recover",
			Aliases: []string{"r"},
			Usage:   "Gets the password back from the guards",
			Action:  get,
		},
	}
	app.Before = func(c *cli.Context) error {
		b, err := ioutil.ReadFile("config.bin")
		if os.IsNotExist(err) {
			return nil
		}
		log.ErrFatal(err, "The config.bin file threw an error")
		_, msg, err := network.UnmarshalRegistered(b)
		log.ErrFatal(err, "UnmarshalRegistered messeed up")
		var ok bool
		db, ok = msg.(*Database)
		if !ok {
			log.Fatal("The message was improperly converted")
		}
		return nil
	}
	app.Run(os.Args)
}
Exemplo n.º 9
0
// loadConfigOrFail tries to load the config and fails if it doesn't succeed.
// If a configuration has been loaded, it will update the config and propose
// part of the identity.
func loadConfigOrFail(c *cli.Context) *ciscConfig {
	cfg, loaded := loadConfig(c)
	if !loaded {
		log.Fatal("Couldn't load configuration-file")
	}
	log.ErrFatal(cfg.ConfigUpdate())
	log.ErrFatal(cfg.ProposeUpdate())
	return cfg
}
Exemplo n.º 10
0
func verifyFile(c *cli.Context) error {
	if len(c.Args().First()) == 0 {
		log.Fatal("Please give the 'msgFile'", 1)
	}
	sigOrEmpty := c.String("signature")
	err := verify(c.Args().First(), sigOrEmpty, c.String(optionGroup))
	verifyPrintResult(err)
	return nil
}
Exemplo n.º 11
0
func idDel(c *cli.Context) error {
	if c.NArg() == 0 {
		log.Fatal("Please give device to delete")
	}
	cfg := loadConfigOrFail(c)
	dev := c.Args().First()
	if _, ok := cfg.Config.Device[dev]; !ok {
		log.Error("Didn't find", dev, "in config. Available devices:")
		configList(c)
		log.Fatal("Device not found in config.")
	}
	prop := cfg.GetProposed()
	delete(prop.Device, dev)
	for _, s := range cfg.Config.GetSuffixColumn("ssh", dev) {
		delete(prop.Data, "ssh:"+dev+":"+s)
	}
	cfg.proposeSendVoteUpdate(prop)
	return nil
}
Exemplo n.º 12
0
func kvAdd(c *cli.Context) error {
	cfg := loadConfigOrFail(c)
	if c.NArg() < 2 {
		log.Fatal("Please give a key value pair")
	}
	key := c.Args().Get(0)
	value := c.Args().Get(1)
	prop := cfg.GetProposed()
	prop.Data[key] = value
	log.ErrFatal(cfg.ProposeSend(prop))
	return cfg.saveConfig(c)
}
Exemplo n.º 13
0
// Reads the group-file and returns it
func getGroup(c *cli.Context) *config.Group {
	gfile := c.Args().Get(0)
	gr, err := os.Open(gfile)
	log.ErrFatal(err)
	defer gr.Close()
	groups, err := config.ReadGroupDescToml(gr)
	log.ErrFatal(err)
	if groups == nil || groups.Roster == nil || len(groups.Roster.List) == 0 {
		log.Fatal("No servers found in roster from", gfile)
	}
	return groups
}
Exemplo n.º 14
0
// Setup implements onet.Simulation interface. It checks on the availability
// of the block-file and downloads it if missing. Then the block-file will be
// copied to the simulation-directory
func (e *Simulation) Setup(dir string, hosts []string) (*onet.SimulationConfig, error) {
	err := blockchain.EnsureBlockIsAvailable(dir)
	if err != nil {
		log.Fatal("Couldn't get block:", err)
	}
	sc := &onet.SimulationConfig{}
	e.CreateRoster(sc, hosts, 2000)
	err = e.CreateTree(sc)
	if err != nil {
		return nil, err
	}
	return sc, nil
}
Exemplo n.º 15
0
func sshDel(c *cli.Context) error {
	cfg := loadConfigOrFail(c)
	_, sshConfig := sshDirConfig(c)
	if c.NArg() == 0 {
		log.Fatal("Please give alias or host to delete from ssh")
	}
	sc, err := NewSSHConfigFromFile(sshConfig)
	log.ErrFatal(err)
	// Converting ah to a hostname if found in ssh-config
	host := sc.ConvertAliasToHostname(c.Args().First())
	if len(cfg.Config.GetValue("ssh", cfg.DeviceName, host)) == 0 {
		log.Error("Didn't find alias or host", host, "here is what I know:")
		sshLs(c)
		log.Fatal("Unknown alias or host.")
	}

	sc.DelHost(host)
	err = ioutil.WriteFile(sshConfig, []byte(sc.String()), 0600)
	log.ErrFatal(err)
	prop := cfg.GetProposed()
	delete(prop.Data, "ssh:"+cfg.DeviceName+":"+host)
	cfg.proposeSendVoteUpdate(prop)
	return cfg.saveConfig(c)
}
Exemplo n.º 16
0
func followDel(c *cli.Context) error {
	if c.NArg() != 1 {
		log.Fatal("Please give id of skipchain to unfollow")
	}
	cfg := loadConfigOrFail(c)
	idBytes, err := hex.DecodeString(c.Args().First())
	log.ErrFatal(err)
	idDel := identity.ID(idBytes)
	newSlice := cfg.Follow[:0]
	for _, id := range cfg.Follow {
		if !bytes.Equal(id.ID, idDel) {
			newSlice = append(newSlice, id)
		}
	}
	cfg.Follow = newSlice
	cfg.writeAuthorizedKeys(c)
	return cfg.saveConfig(c)
}
Exemplo n.º 17
0
/*
 * Commands related to the ssh-handling. All ssh-keys are stored in the
 * identity-sc as
 * ssh:device:server / ssh_public_key
 * where 'ssh' is a fixed string, 'device' is the device where the private
 * key is stored and 'server' the server that should add the public key to
 * its authorized_keys.
 */
func sshAdd(c *cli.Context) error {
	cfg := loadConfigOrFail(c)
	sshDir, sshConfig := sshDirConfig(c)
	if c.NArg() != 1 {
		log.Fatal("Please give the hostname as argument")
	}

	// Get the current configuration
	sc, err := NewSSHConfigFromFile(sshConfig)
	log.ErrFatal(err)

	// Add a new host-entry
	hostname := c.Args().First()
	alias := c.String("a")
	if alias == "" {
		alias = hostname
	}
	filePub := path.Join(sshDir, "key_"+alias+".pub")
	idPriv := "key_" + alias
	filePriv := path.Join(sshDir, idPriv)
	log.ErrFatal(makeSSHKeyPair(c.Int("sec"), filePub, filePriv))
	host := NewSSHHost(alias, "HostName "+hostname,
		"IdentityFile "+filePriv)
	if port := c.String("p"); port != "" {
		host.AddConfig("Port " + port)
	}
	if user := c.String("u"); user != "" {
		host.AddConfig("User " + user)
	}
	sc.AddHost(host)
	err = ioutil.WriteFile(sshConfig, []byte(sc.String()), 0600)
	log.ErrFatal(err)

	// Propose the new configuration
	prop := cfg.GetProposed()
	key := strings.Join([]string{"ssh", cfg.DeviceName, hostname}, ":")
	pub, err := ioutil.ReadFile(filePub)
	log.ErrFatal(err)
	prop.Data[key] = strings.TrimSpace(string(pub))
	cfg.proposeSendVoteUpdate(prop)
	return cfg.saveConfig(c)
}
Exemplo n.º 18
0
func idConnect(c *cli.Context) error {
	log.Info("Connecting")
	name, err := os.Hostname()
	log.ErrFatal(err)
	switch c.NArg() {
	case 2:
		// We'll get all arguments after
	case 3:
		name = c.Args().Get(2)
	default:
		log.Fatal("Please give the following arguments: group.toml id [hostname]", c.NArg())
	}
	group := getGroup(c)
	idBytes, err := hex.DecodeString(c.Args().Get(1))
	log.ErrFatal(err)
	id := identity.ID(idBytes)
	cfg := &ciscConfig{Identity: identity.NewIdentity(group.Roster, 0, name)}
	cfg.AttachToIdentity(id)
	log.Infof("Public key: %s",
		cfg.Proposed.Device[cfg.DeviceName].Point.String())
	return cfg.saveConfig(c)
}
Exemplo n.º 19
0
/*
 * Identity-related commands
 */
func idCreate(c *cli.Context) error {
	log.Info("Creating id")
	if c.NArg() == 0 {
		log.Fatal("Please give at least a group-definition")
	}

	group := getGroup(c)

	name, err := os.Hostname()
	log.ErrFatal(err)
	if c.NArg() > 1 {
		name = c.Args().Get(1)
	}
	log.Info("Creating new blockchain-identity for", name)

	thr := c.Int("threshold")
	cfg := &ciscConfig{Identity: identity.NewIdentity(group.Roster, thr, name)}
	log.ErrFatal(cfg.CreateIdentity())
	log.Infof("IC is %x", cfg.ID)
	log.Infof("Config to be saved: %+v", cfg.Identity.Cothority)
	return cfg.saveConfig(c)
}
Exemplo n.º 20
0
// getpass contacts the guard servers, then gets the passwords and
// reconstructs the secret keys.
func getpass(c *cli.Context, uid []byte, epoch []byte, pass string) {
	if getuser(uid) == nil {
		log.Fatal("Wrong username")
	}

	keys := make([]string, len(db.Cothority.List))
	blind := make([]byte, 12)
	_, err := rand.Read(blind)
	log.ErrFatal(err)
	blinds := saltgen(blind, len(db.Cothority.List))
	iv := getuser(uid).Iv
	// pwhash is the password hash that will be sent to the guard servers
	// with Gu and bi.
	pwhash := abstract.Sum(network.Suite, []byte(pass), getuser(uid).Salt)
	GuHash := abstract.Sum(network.Suite, uid, epoch)
	// creating stream for Scalar.Pick from the hash
	blocky, err := aes.NewCipher(iv)
	log.ErrFatal(err)
	GuStream := cipher.NewCTR(blocky, iv)
	gupoint := network.Suite.Point()
	Gu, _ := gupoint.Pick(GuHash, GuStream)

	for i, si := range db.Cothority.List {
		cl := guard.NewClient()
		// blankpoints needed for computations.
		blankpoint := network.Suite.Point()
		blankscalar := network.Suite.Scalar()
		// pwbytes and blindbytes are actually scalars that are
		// initialized to the values of the bytes.
		pwbytes := network.Suite.Scalar()
		pwbytes.SetBytes(pwhash)
		blindbytes := network.Suite.Scalar()
		blindbytes.SetBytes(blinds[i])
		// The following sections of the code perform the computations
		// to Create Xi, here called sendy.
		blankscalar.Add(pwbytes, blindbytes).MarshalBinary()
		_, err := blankpoint.Mul(Gu, blankscalar.Mul(pwbytes, blindbytes)).MarshalBinary()
		sendy := blankpoint.Mul(Gu, blankscalar.Mul(pwbytes, blindbytes))
		rep, cerr := cl.SendToGuard(si, uid, epoch, sendy)
		log.ErrFatal(cerr)
		// This section of the program removes the blinding factor from
		// the Zi for storage.
		reply, err := blankpoint.Mul(rep.Msg, blankscalar.Inv(blindbytes)).MarshalBinary()
		log.ErrFatal(err)
		// This section Xors the data with the response.
		block, err := aes.NewCipher(reply)
		stream := cipher.NewCTR(block, getuser(uid).Iv)
		msg := make([]byte, len([]byte(getuser(uid).Keys[i])))
		stream.XORKeyStream(msg, []byte(getuser(uid).Keys[i]))
		keys[i] = string(msg)
	}
	k := s.Combine(keys)
	if len(k) == 0 {
		log.Fatal("You entered the wrong password")
	}
	block, err := aes.NewCipher([]byte(k))
	log.ErrFatal(err)
	aesgcm, err := cipher.NewGCM(block)
	log.ErrFatal(err)
	plaintext, err := aesgcm.Open(nil, getuser(uid).Salt, getuser(uid).Data, nil)
	log.ErrFatal(err)
	log.Print(string(plaintext))
}
Exemplo n.º 21
0
func main() {

	cliApp := cli.NewApp()
	cliApp.Name = "Cothorityd server"
	cliApp.Usage = "Serve a cothority"
	cliApp.Version = Version
	serverFlags := []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Value: server.GetDefaultConfigFile(DefaultName),
			Usage: "Configuration file of the server",
		},
		cli.IntFlag{
			Name:  "debug, d",
			Value: 0,
			Usage: "debug-level: 1 for terse, 5 for maximal",
		},
	}

	cliApp.Commands = []cli.Command{
		{
			Name:    "setup",
			Aliases: []string{"s"},
			Usage:   "Setup the configuration for the server (interactive)",
			Action: func(c *cli.Context) error {
				if c.String("config") != "" {
					log.Fatal("Configuration file option can't be used for the 'setup' command")
				}
				if c.String("debug") != "" {
					log.Fatal("[-] Debug option can't be used for the 'setup' command")
				}
				server.InteractiveConfig("cothorityd")
				return nil
			},
		},
		{
			Name:  "server",
			Usage: "Run the cothority server",
			Action: func(c *cli.Context) {
				runServer(c)
			},
			Flags: serverFlags,
		},
		{
			Name:    "check",
			Aliases: []string{"c"},
			Usage:   "Check if the servers in the group definition are up and running",
			Action:  checkConfig,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "g",
					Usage: "Cothority group definition file",
				},
			},
		},
	}
	cliApp.Flags = serverFlags
	// default action
	cliApp.Action = func(c *cli.Context) error {
		runServer(c)
		return nil
	}

	err := cliApp.Run(os.Args)
	log.ErrFatal(err)
}
Exemplo n.º 22
0
func idCheck(c *cli.Context) error {
	log.Fatal("Not yet implemented")
	return nil
}
Exemplo n.º 23
0
func (sm *BitCoSiMessage) UnmarshalBinary(data []byte) error {
	log.Fatal("Don't want to do that")
	return nil
}
Exemplo n.º 24
0
func (tsm BitCoSiMessage) MarshalBinary() ([]byte, error) {
	log.Fatal("Don't want to do that")
	return nil, nil
}
Exemplo n.º 25
0
func (Treq *BlockReply) UnmarshalBinary(data []byte) error {
	log.Fatal("Don't want to do that")
	return nil
}
Exemplo n.º 26
0
func (Treq BlockReply) MarshalBinary() ([]byte, error) {
	log.Fatal("Don't want to do that")
	return nil, nil
}
Exemplo n.º 27
0
func main() {
	app := cli.NewApp()
	app.Name = "CoSi app"
	app.Usage = "Collectively sign a file or verify its signature."
	app.Version = Version
	binaryFlags := []cli.Flag{
		cli.IntFlag{
			Name:  "debug, d",
			Value: 0,
			Usage: "debug-level: 1 for terse, 5 for maximal",
		},
	}

	clientFlags := []cli.Flag{
		cli.StringFlag{
			Name:  optionGroup + ", " + optionGroupShort,
			Value: DefaultGroupFile,
			Usage: "CoSi group definition file",
		},
	}

	serverFlags := []cli.Flag{
		cli.StringFlag{
			Name:  optionConfig + ", " + optionConfigShort,
			Value: server.GetDefaultConfigFile(BinaryName),
			Usage: "Configuration file of the server",
		},
	}
	app.Commands = []cli.Command{
		// BEGIN CLIENT ----------
		{
			Name:    "sign",
			Aliases: []string{"s"},
			Usage:   "Collectively sign a 'msgFile'. The signature is written to STDOUT by default.",
			Action:  signFile,
			Flags: append(clientFlags, []cli.Flag{
				cli.StringFlag{
					Name:  "out, o",
					Usage: "Write signature to 'sig' instead of STDOUT.",
				},
			}...),
		},
		{
			Name:      "verify",
			Aliases:   []string{"v"},
			Usage:     "Verify collective signature of a 'msgFile'. Signature is read by default from STDIN.",
			ArgsUsage: "msgFile",
			Action:    verifyFile,
			Flags: append(clientFlags, []cli.Flag{
				cli.StringFlag{
					Name:  "signature, s",
					Usage: "Read signature from 'sig' instead of STDIN",
				},
			}...),
		},
		{
			Name:    "check",
			Aliases: []string{"c"},
			Usage:   "Check if the servers in the group definition are up and running",
			Action:  checkConfig,
			Flags:   clientFlags,
		},

		// CLIENT END ----------
		// BEGIN SERVER --------
		{
			Name:  "server",
			Usage: "act as Cothority server",
			Action: func(c *cli.Context) error {
				runServer(c)
				return nil
			},
			Flags: serverFlags,
			Subcommands: []cli.Command{
				{
					Name:    "setup",
					Aliases: []string{"s"},
					Usage:   "Setup the configuration for the server (interactive)",
					Action: func(c *cli.Context) error {
						if c.String(optionConfig) != "" {
							log.Fatal("[-] Configuration file option can't be used for the 'setup' command")
						}
						if c.GlobalIsSet("debug") {
							log.Fatal("[-] Debug option can't be used for the 'setup' command")
						}
						server.InteractiveConfig(BinaryName)
						return nil
					},
				},
			},
		},
		// SERVER END ----------
	}

	app.Flags = binaryFlags
	app.Before = func(c *cli.Context) error {
		log.SetDebugVisible(c.GlobalInt("debug"))
		return nil
	}
	err := app.Run(os.Args)
	log.ErrFatal(err)
}
Exemplo n.º 28
0
func configPropose(c *cli.Context) error {
	log.Fatal("Not yet implemented")
	return nil
}
Exemplo n.º 29
0
func kvValue(c *cli.Context) error {
	log.Fatal("Not yet implemented")
	return nil
}
Exemplo n.º 30
0
func sshSync(c *cli.Context) error {
	log.Fatal("Not yet implemented")
	return nil
}