Example #1
0
// create a new KeyDB.
func (ce *CryptEngine) dbCreate(homedir string, iterations int) error {
	keydbname := filepath.Join(homedir, "keys")
	// read passphrase
	log.Infof("read passphrase from fd %d", ce.fileTable.PassphraseFD)
	scanner := bufio.NewScanner(ce.fileTable.PassphraseFP)
	var passphrase []byte
	defer bzero.Bytes(passphrase)
	if scanner.Scan() {
		passphrase = scanner.Bytes()
	} else if err := scanner.Err(); err != nil {
		return log.Error(err)
	}
	// read passphrase again
	log.Infof("read passphrase from fd %d again", ce.fileTable.PassphraseFD)
	var passphrase2 []byte
	defer bzero.Bytes(passphrase2)
	if scanner.Scan() {
		passphrase2 = scanner.Bytes()
	} else if err := scanner.Err(); err != nil {
		return log.Error(err)
	}
	// compare passphrases
	if !bytes.Equal(passphrase, passphrase2) {
		return log.Error("passphrases differ")
	}
	// create keyDB
	log.Infof("create keyDB '%s'", keydbname)
	if err := keydb.Create(keydbname, passphrase, iterations); err != nil {
		return err
	}
	return nil
}
Example #2
0
func (ce *CtrlEngine) openMsgDB(
	homedir string,
) error {
	// read passphrase, if necessary
	if ce.passphrase == nil {
		fmt.Fprintf(ce.fileTable.StatusFP, "read passphrase from fd %d (not echoed)\n",
			ce.fileTable.PassphraseFD)
		log.Infof("read passphrase from fd %d (not echoed)",
			ce.fileTable.PassphraseFD)
		var err error
		ce.passphrase, err = util.Readline(ce.fileTable.PassphraseFP)
		if err != nil {
			return err
		}
		log.Info("done")
	}

	// open msgDB
	msgdbname := filepath.Join(homedir, "msgs")
	log.Infof("open msgDB %s", msgdbname)
	var err error
	ce.msgDB, err = msgdb.Open(msgdbname, ce.passphrase)
	if err != nil {
		return err
	}
	return nil
}
Example #3
0
// loop runs the crypt engine in a loop and reads commands from the file
// descriptor command-fd.
func (ce *CryptEngine) loop(c *cli.Context) {
	if len(c.Args()) > 0 {
		ce.err = fmt.Errorf("cryptengine: unknown command '%s', try 'help'",
			strings.Join(c.Args(), " "))
		return
	}

	log.Info("cryptengine: starting")

	// run command(s)
	log.Infof("read commands from fd %d", ce.fileTable.CommandFD)

	scanner := bufio.NewScanner(ce.fileTable.CommandFP)

	for scanner.Scan() {
		args := []string{ce.app.Name}
		line := scanner.Text()
		if line == "" {
			log.Infof("read empty line")
			continue
		}
		log.Infof("read: %s", line)
		args = append(args, strings.Fields(line)...)
		if err := ce.app.Run(args); err != nil {
			// command execution failed -> issue status and continue
			log.Infof("command execution failed (app): %s", err)
			fmt.Fprintln(ce.fileTable.StatusFP, err)
			continue
		}
		if ce.err != nil {
			if ce.err == errExit {
				// exit requested -> return
				log.Info("cryptengine: stopping (exit requested)")
				fmt.Fprintln(ce.fileTable.StatusFP, "QUITTING")
				ce.err = nil
				return
			}
			// command execution failed -> issue status and continue
			log.Infof("command execution failed (cmd): %s", ce.err)
			fmt.Fprintln(ce.fileTable.StatusFP, ce.err)
			ce.err = nil
		} else {
			log.Info("command successful")
		}
		fmt.Fprintln(ce.fileTable.StatusFP, "READY.")
	}
	if err := scanner.Err(); err != nil {
		ce.err = log.Errorf("cryptengine: %s", err)
	}
	log.Info("cryptengine: stopping (error)")
	return
}
Example #4
0
func (ce *CryptEngine) openKeyDB() error {
	// read passphrase
	log.Infof("read passphrase from fd %d", ce.fileTable.PassphraseFD)
	passphrase, err := util.Readline(ce.fileTable.PassphraseFP)
	if err != nil {
		return err
	}
	defer bzero.Bytes(passphrase)
	log.Info("done")
	// open keyDB
	keydbname := filepath.Join(ce.homedir, "keys")
	log.Infof("open keyDB %s", keydbname)
	ce.keyDB, err = keydb.Open(keydbname, passphrase)
	if err != nil {
		return err
	}
	return nil
}
Example #5
0
func (ce *CtrlEngine) checkUpdates() error {
	commit := ce.config.Map["release.Commit"]
	log.Info("checkUpdates()")
	log.Infof("server: release.Commit: %s", commit)
	log.Infof("binary: release.Commit: %s", release.Commit)
	if release.Commit != commit {
		// parse release date
		tRelease, err := time.Parse(git.Date, ce.config.Map["release.Date"])
		if err != nil {
			return err
		}
		// parse binary date
		tBinary, err := time.Parse(git.Date, release.Date)
		if err != nil {
			return err
		}
		// switch to UTC
		tRelease = tRelease.UTC()
		tBinary = tBinary.UTC()
		log.Infof("server: release.Date: %s", tRelease.Format(time.RFC3339))
		log.Infof("binary: release.Date: %s", tBinary.Format(time.RFC3339))
		// compare dates
		if !tBinary.Before(tRelease) {
			// binary is newer than release -> do nothing
			log.Info("binary is newer than release -> do nothing")
		} else if tBinary.Add(def.UpdateDuration).Before(tRelease) {
			// binary is totally outdated -> force update
			log.Info("binary is totally outdated -> force update")
			return log.Error("ctrlengine: software is outdated, you have to " +
				"update with `mutectrl upkeep update`")
		} else {
			// new version available -> inform user
			log.Info("new version available -> inform user")
			fmt.Fprintf(ce.fileTable.StatusFP, "ctrlengine: software "+
				"available, please update with `mutectrl upkeep update`\n")
		}
	}
	return nil
}
Example #6
0
func (ce *CtrlEngine) upkeepFetchconf(
	msgDB *msgdb.MsgDB,
	homedir string,
	show bool,
	outfp, statfp io.Writer,
) error {
	netDomain, pubkeyStr, configURL := def.ConfigParams()
	log.Infof("fetch config for '%s'", netDomain)
	fmt.Fprintf(statfp, "fetch config for '%s'\n", netDomain)
	publicKey, err := hex.DecodeString(pubkeyStr)
	if err != nil {
		log.Error(err)
	}
	ce.config.PublicKey = publicKey
	ce.config.URLList = "10," + configURL
	ce.config.Timeout = 0 // use default timeout
	if err := ce.config.Update(); err != nil {
		return log.Error(err)
	}
	jsn, err := json.Marshal(ce.config)
	if err != nil {
		return log.Error(err)
	}
	if err := msgDB.AddValue(netDomain, string(jsn)); err != nil {
		return err
	}
	err = msgDB.AddValue("time."+netDomain, strconv.FormatInt(times.Now(), 10))
	if err != nil {
		return err
	}
	// apply new configuration
	if err := def.InitMute(&ce.config); err != nil {
		return err
	}
	// format configuration nicely
	jsn, err = json.MarshalIndent(ce.config, "", "  ")
	if err != nil {
		return log.Error(err)
	}
	// write new configuration file
	if err := writeConfigFile(homedir, netDomain, jsn); err != nil {
		return err
	}
	// show new configuration
	if show {
		fmt.Fprintf(outfp, string(jsn)+"\n")
	}
	return nil
}
Example #7
0
func (ce *CtrlEngine) uidActive(
	c *cli.Context,
	outputFD uintptr,
	outputFP io.Writer,
) error {
	active, err := ce.msgDB.GetValue(msgdb.ActiveUID)
	if err != nil {
		return err
	}
	if active == "" {
		return errors.New("ctrlengine: no active nym in DB")
	}
	log.Infof("write active nym to fd %d", outputFD)
	fmt.Fprintln(outputFP, active)
	return nil
}
Example #8
0
// generate a new nym and store it in keydb.
func (ce *CryptEngine) generate(
	pseudonym string,
	keyserver bool,
	outputfp *os.File,
) error {
	// map pseudonym
	id, domain, err := identity.MapPlus(pseudonym)
	if err != nil {
		return err
	}
	// create new UID
	// TODO: allow different PFS preferences
	var lastEntry string
	if !keyserver {
		// no lastEntry, because this will be the first entry in hashchain
		lastEntry, err = ce.keyDB.GetLastHashChainEntry(domain)
		if err != nil {
			return err
		}
	}
	uid, err := uid.Create(id, false, "", "", uid.Strict, lastEntry,
		cipher.RandReader)
	if err != nil {
		return err
	}
	if !keyserver {
		// store UID in keyDB
		if err := ce.keyDB.AddPrivateUID(uid); err != nil {
			return err
		}
	} else {
		// a private key for the keyserver is not stored in the keyDB
		var out bytes.Buffer
		if err := json.Indent(&out, []byte(uid.JSON()), "", "  "); err != nil {
			return err
		}
		fmt.Fprintln(outputfp, out.String())
		if keyserver {
			fmt.Fprintf(outputfp, "{\"PRIVSIGKEY\": %q}\n", uid.PrivateSigKey())
		}
	}
	log.Infof("nym '%s' generated successfully", id)
	return nil
}
Example #9
0
// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the
// interruptChannel and invokes the registered interruptCallbacks accordingly.
// It also listens for callback registration.  It must be run as a goroutine.
func mainInterruptHandler() {
	// interruptCallbacks is a list of callbacks to invoke when a
	// SIGINT (Ctrl+C) is received.
	var interruptCallbacks []func()

	for {
		select {
		case <-interruptChannel:
			log.Infof("received SIGINT (Ctrl+C). Shutting down...")
			for _, callback := range interruptCallbacks {
				callback()
			}

			// Signal the main goroutine to shutdown.
			ShutdownChannel <- nil

		case handler := <-addHandlerChannel:
			interruptCallbacks = append(interruptCallbacks, handler)
		}
	}
}
Example #10
0
func mutectrlMain() error {
	defer log.Flush()

	// create crypto engine
	ce := ctrlengine.New()
	defer ce.Close()

	// add interrupt handler
	interrupt.AddInterruptHandler(func() {
		log.Infof("gracefully shutting down...")
		ce.Close()
	})

	// start crypto engine
	go func() {
		if err := ce.Start(os.Args); err != nil {
			interrupt.ShutdownChannel <- err
			return
		}
		interrupt.ShutdownChannel <- nil
	}()

	return <-interrupt.ShutdownChannel
}
Example #11
0
// loop runs the CtrlEngine in a loop and reads commands from the file
// descriptor command-fd.
// TODO: actually read from command-fd!
func (ce *CtrlEngine) loop(c *cli.Context) {
	if len(c.Args()) > 0 {
		ce.err = fmt.Errorf("ctrlengine: unknown command '%s', try 'help'",
			strings.Join(c.Args(), " "))
		return
	}

	log.Info("ctrlengine: starting")

	interactive = true

	// run command(s)
	line = liner.NewLiner()
	defer line.Close()
	line.SetCtrlCAborts(true)
	commands := buildCmdList(c.App.Commands, "")
	line.SetCompleter(func(line string) (c []string) {
		for _, command := range commands {
			if strings.HasPrefix(command, line) {
				c = append(c, command)
			}
		}
		return
	})

	for {
		active, err := ce.msgDB.GetValue(msgdb.ActiveUID)
		if err != nil {
			util.Fatal(err)
		}
		if active == "" {
			active = "none"
		}
		fmt.Fprintf(ce.fileTable.StatusFP, "active user ID: %s\n", active)
		fmt.Fprintln(ce.fileTable.StatusFP, "READY.")
		ln, err := line.Prompt("")
		if err != nil {
			if err == liner.ErrPromptAborted {
				fmt.Fprintf(ce.fileTable.StatusFP, "aborting...\n")
			}
			log.Info("ctrlengine: stopping (error)")
			log.Error(err)
			return
		}
		line.AppendHistory(ln)

		args := []string{ce.app.Name}
		if ln == "" {
			log.Infof("read empty line")
			continue
		}
		log.Infof("read: %s", ln)
		// in the loop these global variables are reset, therefore we have to
		// pass them in again
		args = append(args,
			"--homedir", c.GlobalString("homedir"),
			"--logdir", c.GlobalString("logdir"),
			"--loglevel", c.GlobalString("loglevel"),
		)
		args = append(args, strings.Fields(ln)...)
		if err := ce.app.Run(args); err != nil {
			// command execution failed -> issue status and continue
			log.Infof("command execution failed (app): %s", err)
			fmt.Fprintln(ce.fileTable.StatusFP, err)
			continue
		}
		if ce.err != nil {
			if ce.err == errExit {
				// exit requested -> return
				log.Info("ctrlengine: stopping (exit requested)")
				ce.err = nil
				return
			}
			// command execution failed -> issue status and continue
			fmt.Fprintln(ce.fileTable.StatusFP, ce.translateError(ce.err))
			ce.err = nil
		} else {
			log.Info("command successful")
		}
	}
}
Example #12
0
func (ce *CtrlEngine) prepare(
	c *cli.Context,
	openMsgDB, checkUpdates bool,
) error {
	if !ce.prepared {
		// create the necessary directories if they don't already exist
		err := util.CreateDirs(c.GlobalString("homedir"), c.GlobalString("logdir"))
		if err != nil {
			return err
		}

		// initialize logging framework
		err = log.Init(c.GlobalString("loglevel"), "ctrl ",
			c.GlobalString("logdir"), c.GlobalBool("logconsole"))
		if err != nil {
			return err
		}

		// initialize file descriptors
		ce.fileTable, err = descriptors.NewTable(c)
		if err != nil {
			return err
		}

		ce.prepared = true
	}

	log.Infof("prepare(openMsgDB=%s)", strconv.FormatBool(openMsgDB))

	// open MsgDB, if necessary
	if openMsgDB {
		homedir := c.GlobalString("homedir")
		offline := c.GlobalBool("offline")

		// open messsage DB, if necessary
		if ce.msgDB == nil {
			err := ce.openMsgDB(homedir)
			if err != nil {
				return err
			}
		}

		// get config
		if err := ce.getConfig(homedir, offline); err != nil {
			return err
		}

		// check for updates, if necessary
		if checkUpdates {
			if err := ce.checkUpdates(); err != nil {
				return err
			}
		}

		// start wallet
		var err error
		ce.client, err = startWallet(ce.msgDB, offline)
		if err != nil {
			return err
		}
	}

	return nil
}
Example #13
0
// create a new MsgDB and KeyDB.
func (ce *CtrlEngine) dbCreate(
	w, statusfp io.Writer,
	homedir string,
	c *cli.Context,
) error {
	msgdbname := filepath.Join(c.GlobalString("homedir"), "msgs")
	// read passphrase
	fmt.Fprintf(statusfp, "read passphrase from fd %d (not echoed)\n",
		ce.fileTable.PassphraseFD)
	log.Infof("read passphrase from fd %d (not echoed)",
		ce.fileTable.PassphraseFD)
	var (
		scanner     *bufio.Scanner
		passphrase  []byte
		passphrase2 []byte
		err         error
	)
	defer bzero.Bytes(passphrase)
	defer bzero.Bytes(passphrase2)
	isTerminal := terminal.IsTerminal(int(ce.fileTable.PassphraseFD))
	if isTerminal {
		passphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD))
		if err != nil {
			return log.Error(err)
		}
	} else {
		scanner = bufio.NewScanner(ce.fileTable.PassphraseFP)
		if scanner.Scan() {
			passphrase = scanner.Bytes()
		} else if err := scanner.Err(); err != nil {
			return log.Error(err)
		}
	}
	log.Info("done")
	// read passphrase again
	fmt.Fprintf(statusfp, "read passphrase from fd %d again (not echoed)\n",
		ce.fileTable.PassphraseFD)
	log.Infof("read passphrase from fd %d again (not echoed)",
		ce.fileTable.PassphraseFD)
	if isTerminal {
		passphrase2, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD))
		if err != nil {
			return log.Error(err)
		}
	} else {
		if scanner.Scan() {
			passphrase2 = scanner.Bytes()
		} else if err := scanner.Err(); err != nil {
			return log.Error(err)
		}
	}
	log.Info("done")
	// compare passphrases
	if !bytes.Equal(passphrase, passphrase2) {
		return log.Error(ErrPassphrasesDiffer)
	}
	// create msgDB
	log.Infof("create msgDB '%s'", msgdbname)
	if err := msgdb.Create(msgdbname, passphrase, c.Int("iterations")); err != nil {
		return err
	}
	// open msgDB
	msgDB, err := msgdb.Open(msgdbname, passphrase)
	if err != nil {
		return err
	}
	defer msgDB.Close()
	// configure to make sure mutecrypt has config file
	err = ce.upkeepFetchconf(msgDB, homedir, false, nil, statusfp)
	if err != nil {
		return err
	}
	// create keyDB
	log.Info("create keyDB")
	if err := createKeyDB(c, w, ce.fileTable.OutputFD, passphrase); err != nil {
		return err
	}
	// status
	fmt.Fprintf(statusfp, "database files created\n")
	log.Info("database files created")
	// determine private walletKey
	walletKey := c.String("walletkey")
	if walletKey == "" {
		// generate wallet key
		_, privateKey, err := ed25519.GenerateKey(cipher.RandReader)
		if err != nil {
			return err
		}
		walletKey = base64.Encode(privateKey[:])
	}
	// store wallet key
	if err := msgDB.AddValue(msgdb.WalletKey, walletKey); err != nil {
		return err
	}
	// print wallet key
	if err := printWalletKey(w, walletKey); err != nil {
		return err
	}
	return nil
}
Example #14
0
func (ce *CryptEngine) registerOrUpdate(
	pseudonym, token, command, verb string,
) error {
	// map pseudonym
	id, domain, err := identity.MapPlus(pseudonym)
	if err != nil {
		return err
	}
	// TODO: check token?
	// get UID from keyDB
	msg, messageReply, err := ce.keyDB.GetPrivateUID(id, false)
	if err != nil {
		return err
	}
	if messageReply != nil {
		return log.Errorf("cryptengine: UID has already been %s", verb)
	}
	// get JSON-RPC client and capabilities
	client, caps, err := ce.cache.Get(domain, ce.keydPort, ce.keydHost,
		ce.homedir, "KeyRepository."+command)
	if err != nil {
		return err
	}
	// register/update UID with key server
	content := make(map[string]interface{})
	content["UIDMessage"] = msg
	content["Token"] = token
	reply, err := client.JSONRPCRequest("KeyRepository."+command, content)
	if err != nil {
		return err
	}
	rep, ok := reply["UIDMessageReply"].(map[string]interface{})
	if !ok {
		return log.Errorf("cryptengine: %s reply has the wrong type", command)
	}

	// marshal the unstructured UIDMessageReply into a JSON byte array
	jsn, err := json.Marshal(rep)
	if err != nil {
		return err
	}
	// unmarshal the JSON byte array back into a UIDMessageReply
	msgReply, err := uid.NewJSONReply(string(jsn))
	if err != nil {
		return err
	}

	// store reply first to have proof, if the key server is cheating
	if err := ce.keyDB.AddPrivateUIDReply(msg, msgReply); err != nil {
		return err
	}

	// verify reply
	// TODO: keyserver can return more than one SIGPUBKEY
	if err := msgReply.VerifySrvSig(msg, caps.SIGPUBKEYS[0]); err != nil {
		return err
	}

	log.Infof("nym '%s' %s successfully", id, verb)
	return nil
}
Example #15
0
func (pe *ProtoEngine) fetch(
	output io.Writer,
	status io.Writer,
	server string,
	lastMessageTime int64,
	command io.Reader,
) error {
	// read passphrase
	log.Infof("read private key from fd %d", pe.fileTable.PassphraseFD)
	pks, err := util.Readline(pe.fileTable.PassphraseFP)
	if err != nil {
		return err
	}
	log.Info("done")
	pk, err := base64.Decode(string(pks))
	if err != nil {
		return log.Error(err)
	}
	var privkey [ed25519.PrivateKeySize]byte
	copy(privkey[:], pk)
	log.Debugf("lastMessageTime=%d", lastMessageTime)
	messages, err := client.ListMessages(&privkey, lastMessageTime, server,
		def.CACert)
	if err != nil {
		// TODO: handle this better
		if err.Error() == "accountdb: Nothing found" {
			// no messages found
			log.Info("write: NONE")
			fmt.Fprintln(status, "NONE")
			return nil
		}
		return log.Error(err)
	}
	/*
		for _, message := range messages {
			messageID := base64.Encode(message.MessageID)
			log.Debugf("messageID=%s, ReceiveTime=%d, ReadTime=%d", messageID,
				message.ReceiveTime, message.ReadTime)
		}
	*/
	scanner := bufio.NewScanner(command)
	for _, message := range messages {
		msg, err := client.FetchMessage(&privkey, message.MessageID, server,
			def.CACert)
		if err != nil {
			return log.Error(err)
		}
		messageID := base64.Encode(message.MessageID)
		log.Debugf("write: MESSAGEID:\t%s", messageID)
		fmt.Fprintf(status, "MESSAGEID:\t%s\n", messageID)
		var command string
		if scanner.Scan() {
			command = scanner.Text()
		} else {
			return log.Error("protoengine: expecting command input")
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
		}
		if command == "NEXT" {
			log.Debug("read: NEXT")
			enc := base64.Encode(msg)
			if _, err := io.WriteString(output, enc); err != nil {
				return log.Error(err)
			}
			log.Debugf("write: LENGTH:\t%d", len(enc))
			fmt.Fprintf(status, "LENGTH:\t%d\n", len(enc))
			log.Debugf("write: RECEIVETIME:\t%d", message.ReceiveTime)
			fmt.Fprintf(status, "RECEIVETIME:\t%d\n", message.ReceiveTime)
		} else if command == "QUIT" {
			log.Debug("read: QUIT")
			return nil
		} else {
			return log.Errorf("protoengine: unknown command '%s'", command)
		}
	}
	// no more messages
	log.Info("write: NONE")
	fmt.Fprintln(status, "NONE")
	return nil
}
Example #16
0
func mutecryptNewUID(
	c *cli.Context,
	passphrase []byte,
	id, domain, host, mixaddress, nymaddress string,
	client *client.Client,
) error {
	log.Infof("mutecryptNewUID(): id=%s, domain=%s", id, domain)
	args := []string{
		"--homedir", c.GlobalString("homedir"),
		"--loglevel", c.GlobalString("loglevel"),
		"--logdir", c.GlobalString("logdir"),
	}
	if host != "" {
		args = append(args,
			"--keyhost", host,
			"--keyport", ":8080") // TODO: remove keyport hack!
	}
	cmd := exec.Command("mutecrypt", args...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}
	scanner := bufio.NewScanner(stderr)
	passphraseReader, passphraseWriter, err := os.Pipe()
	if err != nil {
		return err
	}
	cmd.ExtraFiles = append(cmd.ExtraFiles, passphraseReader)
	commandReader, commandWriter, err := os.Pipe()
	if err != nil {
		return err
	}
	cmd.ExtraFiles = append(cmd.ExtraFiles, commandReader)

	// generate UID
	_, err = io.WriteString(commandWriter, strings.Join([]string{
		"uid", "generate", "--id", id + "\n",
	}, " "))
	if err != nil {
		return err
	}

	// start process
	if err := cmd.Start(); err != nil {
		return err
	}

	// write passphrase
	plen := len(passphrase)
	buf := make([]byte, plen+1)
	defer bzero.Bytes(buf)
	copy(buf, passphrase)
	copy(buf[plen:], []byte("\n"))
	if _, err := passphraseWriter.Write(buf); err != nil {
		return err
	}
	passphraseWriter.Close()

	// check for errors on stderr
	for scanner.Scan() {
		line := scanner.Text()
		if line != "READY." {
			return errors.New(line)
		}
		break
	}
	if err := scanner.Err(); err != nil {
		return err
	}

	// get capabilities
	args = []string{"caps", "show", "--domain", domain}
	if host := c.String("host"); host != "" {
		args = append(args, "--host", host)
	}
	args = append(args, "\n")
	_, err = io.WriteString(commandWriter, strings.Join(args, " "))
	if err != nil {
		return err
	}
	for scanner.Scan() {
		line := scanner.Text()
		if line != "READY." {
			return errors.New(line)
		}
		break
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	var caps capabilities.Capabilities
	decoder := json.NewDecoder(stdout)
	if err := decoder.Decode(&caps); err != nil {
		return err
	}
	/*
		// pretty-print capabilities
		jsn, err := json.MarshalIndent(caps, "", "  ")
		if err != nil {
			return err
		}
		fmt.Println(string(jsn))
	*/

	owner, err := decodeED25519PubKeyBase64(caps.TKNPUBKEY)
	if err != nil {
		return err
	}
	// get token from wallet
	token, err := wallet.GetToken(client, "UID", owner)
	if err != nil {
		return err
	}

	// try to register UID
	_, err = io.WriteString(commandWriter, strings.Join([]string{
		"uid", "register",
		"--id", id,
		"--token", base64.Encode(token.Token) + "\n",
	}, " "))
	if err != nil {
		client.UnlockToken(token.Hash)
		return err
	}

	var cryptErr error
	for scanner.Scan() {
		line := scanner.Text()
		if line != "READY." {
			cryptErr = errors.New(line)
		} else {
			break
		}
	}
	if err := scanner.Err(); err != nil {
		client.UnlockToken(token.Hash)
		return err
	}

	// delete UID, if registration was not successful
	if cryptErr != nil {
		client.UnlockToken(token.Hash)
		_, err = io.WriteString(commandWriter, strings.Join([]string{
			"uid", "delete",
			"--force",
			"--id", id + "\n",
		}, " "))
		if err != nil {
			return err
		}
		for scanner.Scan() {
			line := scanner.Text()
			if line != "READY." {
				return errors.New(line)
			}
			break
		}
		if err := scanner.Err(); err != nil {
			return err
		}
	} else {
		client.DelToken(token.Hash)
	}

	// add KeyInit messages
	token, err = wallet.GetToken(client, "Message", owner)
	if err != nil {
		return err
	}
	_, err = io.WriteString(commandWriter, strings.Join([]string{
		"keyinit", "add",
		"--id", id,
		"--mixaddress", mixaddress,
		"--nymaddress", nymaddress,
		"--token", base64.Encode(token.Token) + "\n",
	}, " "))
	if err != nil {
		client.UnlockToken(token.Hash)
		return err
	}
	for scanner.Scan() {
		line := scanner.Text()
		if line != "READY." {
			return errors.New(line)
		}
		break
	}
	if err := scanner.Err(); err != nil {
		client.UnlockToken(token.Hash)
		return err
	}
	client.DelToken(token.Hash)

	// quit mutecrypt
	if _, err := io.WriteString(commandWriter, "quit\n"); err != nil {
		return err
	}
	for scanner.Scan() {
		line := scanner.Text()
		if line != "QUITTING" {
			return errors.New(line)
		}
		break
	}
	if err := scanner.Err(); err != nil {
		return err
	}

	if err := cmd.Wait(); err != nil {
		return err
	}

	// propagate error
	if cryptErr != nil {
		return cryptErr
	}

	return nil
}
Example #17
0
func (ce *CtrlEngine) upkeepUpdate(
	homedir string,
	/* source, binary bool, */
	outfp, statfp io.Writer,
) error {
	log.Info("upkeepUpdate()")
	// make sure we have the most current config
	if err := ce.upkeepFetchconf(ce.msgDB, homedir, false, outfp, statfp); err != nil {
		return err
	}
	commit := ce.config.Map["release.Commit"]
	log.Infof("server: release.Commit: %s", commit)
	log.Infof("binary: release.Commit: %s", release.Commit)
	if release.Commit == commit {
		log.Info("Mute is up-to-date")
		fmt.Fprintf(statfp, "Mute is up-to-date\n")
		return nil
	}
	// parse release date
	tRelease, err := time.Parse(git.Date, ce.config.Map["release.Date"])
	if err != nil {
		return err
	}
	// parse binary date
	tBinary, err := time.Parse(git.Date, release.Date)
	if err != nil {
		return err
	}
	// switch to UTC
	tRelease = tRelease.UTC()
	tBinary = tBinary.UTC()
	log.Infof("server: release.Date: %s", tRelease.Format(time.RFC3339))
	log.Infof("binary: release.Date: %s", tBinary.Format(time.RFC3339))
	// compare dates
	if tBinary.After(tRelease) {
		log.Info("commits differ, but binary is newer than release date")
		fmt.Fprintf(statfp, "commits differ, but binary is newer than release date\n")
		fmt.Fprintf(statfp, "are you running a developer version?\n")
		return nil
	}
	/*
		// commits differ and release date is more current than binary -> update
		if !source && !binary {
			// try to determine update mode via mutegenerate
			// (should only exist for source releases)
			dir, err := exec.LookPath(os.Args[0])
			if err != nil {
				return err
			}
			dir = filepath.Join(dir, "..")
			cmd := exec.Command(filepath.Join(dir, "mutegenerate"), "-t")
			if err := cmd.Run(); err != nil {
				binary = true
			} else {
				source = true
			}
		}
		if source {
	*/
	log.Info("call updateMuteFromSource()")
	if err := updateMuteFromSource(outfp, statfp, commit); err != nil {
		return err
	}
	/*
		} else {
			if err := updateMuteBinaries(outfp, statfp); err != nil {
				return err
			}
		}
	*/
	// after a successful we exit
	return errExit
}
Example #18
0
// rekey MsgDB and KeyDB.
func (ce *CtrlEngine) dbRekey(statusfp io.Writer, c *cli.Context) error {
	msgdbname := filepath.Join(c.GlobalString("homedir"), "msgs")
	// read old passphrase
	fmt.Fprintf(statusfp, "read old passphrase from fd %d (not echoed)\n",
		ce.fileTable.PassphraseFD)
	log.Infof("read old passphrase from fd %d (not echoed)",
		ce.fileTable.PassphraseFD)
	var (
		scanner        *bufio.Scanner
		oldPassphrase  []byte
		newPassphrase  []byte
		newPassphrase2 []byte
		err            error
	)
	defer bzero.Bytes(oldPassphrase)
	defer bzero.Bytes(newPassphrase)
	defer bzero.Bytes(newPassphrase2)
	isTerminal := terminal.IsTerminal(int(ce.fileTable.PassphraseFD))
	if isTerminal {
		oldPassphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD))
		if err != nil {
			return log.Error(err)
		}
	} else {
		scanner = bufio.NewScanner(ce.fileTable.PassphraseFP)
		if scanner.Scan() {
			oldPassphrase = scanner.Bytes()
		} else if err := scanner.Err(); err != nil {
			return log.Error(err)
		}
	}
	log.Info("done")
	// read new passphrase
	fmt.Fprintf(statusfp, "read new passphrase from fd %d (not echoed)\n",
		ce.fileTable.PassphraseFD)
	log.Infof("read new passphrase from fd %d (not echoed)",
		ce.fileTable.PassphraseFD)
	if isTerminal {
		newPassphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD))
		if err != nil {
			return log.Error(err)
		}
	} else {
		if scanner.Scan() {
			newPassphrase = scanner.Bytes()
		} else if err := scanner.Err(); err != nil {
			return log.Error(err)
		}
	}
	log.Info("done")
	// read new passphrase again
	fmt.Fprintf(statusfp, "read new passphrase from fd %d again (not echoed)\n",
		ce.fileTable.PassphraseFD)
	log.Infof("read new passphrase from fd %d again (not echoed)",
		ce.fileTable.PassphraseFD)
	if isTerminal {
		newPassphrase2, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD))
		if err != nil {
			return log.Error(err)
		}
	} else {
		if scanner.Scan() {
			newPassphrase2 = scanner.Bytes()
		} else if err := scanner.Err(); err != nil {
			return log.Error(err)
		}
	}
	log.Info("done")
	// compare new passphrases
	if !bytes.Equal(newPassphrase, newPassphrase2) {
		return log.Error(ErrPassphrasesDiffer)
	}
	// rekey msgDB
	log.Infof("rekey msgDB '%s'", msgdbname)
	if err := msgdb.Rekey(msgdbname, oldPassphrase, newPassphrase, c.Int("iterations")); err != nil {
		return err
	}
	// rekey keyDB
	log.Info("rekey keyDB")
	if err := rekeyKeyDB(c, oldPassphrase, newPassphrase); err != nil {
		return err
	}
	return nil
}