Пример #1
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
}
Пример #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
}
Пример #3
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
}
Пример #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
}
Пример #5
0
func (pe *ProtoEngine) deliver(statusfp io.Writer, r io.Reader) error {
	enc, err := ioutil.ReadAll(r)
	if err != nil {
		return log.Error(err)
	}
	var mm client.MessageMarshalled
	mm, err = base64.Decode(string(enc))
	if err != nil {
		return log.Error(err)
	}
	messageOut, err := mm.Unmarshal().Deliver()
	if err != nil {
		if messageOut.Resend {
			log.Info("write: RESEND:\t%s", err.Error())
			fmt.Fprintf(statusfp, "RESEND:\t%s\n", err.Error())
			return nil
		}
		return log.Error(err)
	}
	return nil
}
Пример #6
0
func (ce *CtrlEngine) upkeepAll(
	c *cli.Context,
	unmappedID,
	period string,
	statfp io.Writer,
) error {
	mappedID, err := identity.Map(unmappedID)
	if err != nil {
		return err
	}

	exec, now, err := checkExecution(mappedID, period,
		func(mappedID string) (int64, error) {
			return ce.msgDB.GetUpkeepAll(mappedID)
		})
	if err != nil {
		return err
	}
	if !exec {
		log.Info(statfp, "ctrlengine: upkeep all not due")
		fmt.Fprintf(statfp, "ctrlengine: upkeep all not due\n")
		return nil
	}

	// `upkeep accounts`
	if err := ce.upkeepAccounts(unmappedID, period, "2160h", statfp); err != nil {
		return err
	}

	// TODO: call all upkeep tasks in mutecrypt

	// record time of execution
	if err := ce.msgDB.SetUpkeepAll(mappedID, now); err != nil {
		return err
	}
	return nil
}
Пример #7
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
}
Пример #8
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")
		}
	}
}
Пример #9
0
// This example shows when and how to use the info log level.
func Example_info() {
	// server receives message
	log.Info("server: message received")
}
Пример #10
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
}
Пример #11
0
func muteprotoFetch(
	myID, contactID string,
	msgDB *msgdb.MsgDB,
	c *cli.Context,
	privkey, server string,
	lastMessageTime int64,
) (newMessageTime int64, err error) {
	log.Debug("muteprotoFetch()")
	args := []string{
		"--homedir", c.GlobalString("homedir"),
		"--loglevel", c.GlobalString("loglevel"),
		"--logdir", c.GlobalString("logdir"),
		"fetch",
		"--server", server,
		"--last-message-time", strconv.FormatInt(lastMessageTime, 10),
	}
	cmd := exec.Command("muteproto", args...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return 0, err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return 0, err
	}
	ppR, ppW, err := os.Pipe()
	if err != nil {
		return 0, err
	}
	defer ppR.Close()
	ppW.Write([]byte(privkey))
	ppW.Close()
	cmd.ExtraFiles = append(cmd.ExtraFiles, ppR)
	cmdR, cmdW, err := os.Pipe()
	if err != nil {
		return 0, err
	}
	defer cmdR.Close()
	defer cmdW.Close()
	cmd.ExtraFiles = append(cmd.ExtraFiles, cmdR)
	if err := cmd.Start(); err != nil {
		return 0, err
	}
	var outbuf bytes.Buffer
	status := bufio.NewReader(stderr)
	input := make(chan []byte)
	go func() {
		for {
			buf := make([]byte, 4096)
			n, err := stdout.Read(buf)
			if n > 0 {
				input <- buf[:n]
			}
			if err != nil {
				if err == io.EOF {
					return
				}
				log.Error(err)
				return
			}
		}
	}()
	firstMessage := true
	cache, err := msgDB.GetMessageIDCache(myID, contactID)
	if err != nil {
		return 0, err
	}
	for {
		// read status output
		line, err := status.ReadString('\n')
		if err != nil {
			return 0, log.Error(err)
		}
		line = strings.TrimSpace(line)
		if line == "NONE" {
			log.Debug("read: NONE")
			break
		}
		if strings.HasSuffix(line, "accountdb: nothing found") {
			log.Info("account has no messages")
			return 0, nil
		}
		parts := strings.Split(line, "\t")
		if len(parts) != 2 || parts[0] != "MESSAGEID:" {
			return 0, log.Errorf("ctrlengine: MESSAGEID line expected from muteproto, got: %s", line)
		}
		messageID := parts[1]
		log.Debugf("read: MESSAGEID:\t%s", messageID)
		if cache[messageID] {
			// message known -> abort fetching messages and remove old IDs from cache
			log.Debug("write: QUIT")
			fmt.Fprintln(cmdW, "QUIT")
			err := msgDB.RemoveMessageIDCache(myID, contactID, messageID)
			if err != nil {
				return 0, log.Error(err)
			}
			break
		} else {
			// message unknown -> fetch it and add messageID to cache
			log.Debug("write: NEXT")
			fmt.Fprintln(cmdW, "NEXT")
			err := msgDB.AddMessageIDCache(myID, contactID, messageID)
			if err != nil {
				return 0, log.Error(err)
			}
		}
		// read message
		stop := make(chan uint64)
		done := make(chan bool)
		go func() {
			for {
				select {
				case buf := <-input:
					outbuf.Write(buf)
				case length := <-stop:
					for uint64(outbuf.Len()) < length {
						buf := <-input
						outbuf.Write(buf)
					}
					done <- true
					return
				}
			}
		}()
		// read LENGTH
		line, err = status.ReadString('\n')
		if err != nil {
			return 0, log.Error(err)
		}
		parts = strings.Split(strings.TrimRight(line, "\n"), "\t")
		if len(parts) != 2 || parts[0] != "LENGTH:" {
			return 0, log.Errorf("ctrlengine: LENGTH line expected from muteproto, got: %s", line)
		}
		length, err := strconv.ParseUint(parts[1], 10, 64)
		if err != nil {
			return 0, log.Error(err)
		}
		log.Debugf("read: LENGTH:\t%d", length)
		// read RECEIVETIME
		line, err = status.ReadString('\n')
		if err != nil {
			return 0, log.Error(err)
		}
		parts = strings.Split(strings.TrimRight(line, "\n"), "\t")
		if len(parts) != 2 || parts[0] != "RECEIVETIME:" {
			return 0, log.Errorf("ctrlengine: RECEIVETIME line expected from muteproto, got: %s", line)
		}
		receiveTime, err := strconv.ParseInt(parts[1], 10, 64)
		if err != nil {
			return 0, log.Error(err)
		}
		log.Debugf("read: RECEIVETIME:\t%d", receiveTime)

		stop <- length
		<-done
		err = msgDB.AddInQueue(myID, contactID, receiveTime, outbuf.String())
		if err != nil {
			return 0, err
		}
		if firstMessage {
			newMessageTime = receiveTime
			firstMessage = false
		}
		outbuf.Reset()
	}
	if err := cmd.Wait(); err != nil {
		return 0, err
	}
	return
}
Пример #12
0
func (ce *CtrlEngine) msgAdd(
	c *cli.Context,
	from, to, file string,
	mailInput, permanentSignature bool,
	attachments []string,
	minDelay, maxDelay int32,
	line *liner.State,
	r io.Reader,
) error {
	fromMapped, err := identity.Map(from)
	if err != nil {
		return err
	}
	prev, _, err := ce.msgDB.GetNym(fromMapped)
	if err != nil {
		return err
	}
	if prev == "" {
		return log.Errorf("user ID %s not found", from)
	}

	// TODO: handle attachments
	var msg []byte
	if file != "" {
		// read message from file
		msg, err = ioutil.ReadFile(file)
		if err != nil {
			return log.Error(err)
		}
	} else if line != nil {
		// read message from terminal
		fmt.Fprintln(ce.fileTable.StatusFP,
			"type message (end with Ctrl-D on empty line):")
		var inbuf bytes.Buffer
		for {
			ln, err := line.Prompt("")
			if err != nil {
				if err == io.EOF {
					break
				}
				return log.Error(err)
			}
			inbuf.WriteString(ln + "\n")
		}
		msg = inbuf.Bytes()
	} else {
		// read message from stdin
		msg, err = ioutil.ReadAll(r)
		if err != nil {
			return log.Error(err)
		}
	}

	if mailInput {
		recipient, message, err := mail.Parse(bytes.NewBuffer(msg))
		if err != nil {
			return err
		}
		to = recipient
		msg = []byte(message)
	}

	toMapped, err := identity.Map(to)
	if err != nil {
		return err
	}
	prev, _, contactType, err := ce.msgDB.GetContact(fromMapped, toMapped)
	if err != nil {
		return err
	}
	if prev == "" || contactType == msgdb.GrayList || contactType == msgdb.BlackList {
		return log.Errorf("contact %s not found (for user ID %s)", to, from)
	}

	// store message in message DB
	now := times.Now()
	err = ce.msgDB.AddMessage(fromMapped, toMapped, now, true, string(msg),
		permanentSignature, minDelay, maxDelay)
	if err != nil {
		return err
	}

	log.Info("message added")
	if line != nil {
		fmt.Fprintln(ce.fileTable.StatusFP, "message added")
	}

	return nil
}
Пример #13
0
// InitMute initializes Mute with the configuration from config.
func InitMute(config *configclient.Config) error {
	log.Info("initialize Mute")
	var ok bool
	rpcPort := config.Map["mixclient.RPCPort"]
	if rpcPort != "" {
		mixclient.RPCPort = rpcPort
	}
	var mixAddress string
	mixAddress, ok = config.Map["mixclient.MixAddress"]
	if !ok {
		return log.Error("config.Map[\"mixclient.MixAddress\"] undefined")
	}
	util.MixAddress = mixAddress
	mixclient.DefaultAccountServer, ok = config.Map["mixclient.AccountServer"]
	if !ok {
		return log.Error("config.Map[\"mixclient.AccountServer\"] undefined")
	}
	mixclient.DefaultSender, ok = config.Map["mixclient.Sender"]
	if !ok {
		return log.Error("config.Map[\"mixclient.Sender\"] undefined")
	}
	walletrpc.ServiceURL, ok = config.Map["walletrpc.ServiceURL"]
	if !ok {
		return log.Error("config.Map[\"walletrpc.ServiceURL\"] undefined")
	}
	keylookup.ServiceURL, ok = config.Map["keylookup.ServiceURL"]
	if !ok {
		return log.Error("config.Map[\"keylookup.ServiceURL\"] undefined")
	}
	guardrpc.ServiceURL, ok = config.Map["guardrpc.ServiceURL"]
	if !ok {
		return log.Error("config.Map[\"guardrpc.ServiceURL\"] undefined")
	}
	var trustRoot string
	trustRoot, ok = config.Map["serviceguard.TrustRoot"]
	if !ok {
		return log.Error("config.Map[\"serviceguard.TrustRoot\"] undefined")
	}
	var err error
	client.TrustRoot, err = decodeED25519PubKey(trustRoot)
	if err != nil {
		return err
	}

	// set msg.CleanupTime
	mm, ok := config.Map["mix.MaxDelay"]
	if !ok {
		return log.Error("config.Map[\"mix.MaxDelay\"] undefined")
	}
	mixMax, err := strconv.ParseUint(mm, 10, 64)
	if err != nil {
		return log.Error("cannot parse config.Map[\"mix.MaxDelay\"]")
	}
	msg.CleanupTime = 2*msg.SendTime + 2*mixMax

	// set CA cert
	CACert = config.CACert

	// set configuration map
	ConfigMap = config.Map

	// muteaccd owner
	var owner string
	owner, ok = config.Map["muteaccd.owner"]
	if !ok {
		return log.Error("config.Map[\"muteaccd.owner\"] undefined")
	}
	AccdOwner, err = decodeED25519PubKey(owner)
	if err != nil {
		return err
	}

	// muteaccd usage
	AccdUsage, ok = config.Map["muteaccd.usage"]
	if !ok {
		return log.Error("config.Map[\"muteaccd.usage\"] undefined")
	}

	return nil
}
Пример #14
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
}
Пример #15
0
func (ce *CtrlEngine) upkeepAccounts(
	unmappedID, period, remaining string,
	statfp io.Writer,
) error {
	mappedID, err := identity.Map(unmappedID)
	if err != nil {
		return err
	}

	exec, now, err := checkExecution(mappedID, period,
		func(mappedID string) (int64, error) {
			return ce.msgDB.GetUpkeepAccounts(mappedID)
		})
	if err != nil {
		return err
	}
	if !exec {
		log.Info(statfp, "ctrlengine: upkeep accounts not due")
		fmt.Fprintf(statfp, "ctrlengine: upkeep accounts not due\n")
		return nil
	}

	remain, err := time.ParseDuration(remaining)
	if err != nil {
		return err
	}

	contacts, err := ce.msgDB.GetAccounts(mappedID)
	if err != nil {
		return err
	}

	for _, contact := range contacts {
		privkey, server, _, _, _, _, err := ce.msgDB.GetAccount(mappedID, contact)
		if err != nil {
			return err
		}
		last, err := ce.msgDB.GetAccountTime(mappedID, contact)
		if err != nil {
			return err
		}
		if last == 0 {
			last, err = mixclient.AccountStat(privkey, server, def.CACert)
			if err != nil {
				return err
			}
			err := ce.msgDB.SetAccountTime(mappedID, contact, last)
			if err != nil {
				return err
			}
		}
		if times.Now()+int64(remain.Seconds()) >= last {
			token, err := wallet.GetToken(ce.client, def.AccdUsage, def.AccdOwner)
			if err != nil {
				return err
			}
			_, err = mixclient.PayAccount(privkey, token.Token, server, def.CACert)
			if err != nil {
				ce.client.UnlockToken(token.Hash)
				return log.Error(err)
			}
			ce.client.DelToken(token.Hash)
			last, err = mixclient.AccountStat(privkey, server, def.CACert)
			if err != nil {
				return err
			}
			err = ce.msgDB.SetAccountTime(mappedID, contact, last)
			if err != nil {
				return err
			}
		}
	}

	// record time of execution
	if err := ce.msgDB.SetUpkeepAccounts(mappedID, now); err != nil {
		return err
	}

	return nil
}
Пример #16
0
func (ce *CtrlEngine) procInQueue(c *cli.Context, host string) error {
	log.Debug("procInQueue()")
	for {
		// get message from msgDB
		iqIdx, myID, contactID, msg, envelope, err := ce.msgDB.GetInQueue()
		if err != nil {
			return err
		}
		if myID == "" {
			log.Debug("no more messages in inqueue")
			break // no more messages in inqueue
		}
		if envelope {
			log.Debugf("decrypt envelope (iqIdx=%d)", iqIdx)
			// decrypt envelope
			message, err := base64.Decode(msg)
			if err != nil {
				return log.Error(err)
			}
			privkey, server, secret, _, _, _, err := ce.msgDB.GetAccount(myID, contactID)
			if err != nil {
				return err
			}
			receiveTemplate := nymaddr.AddressTemplate{
				Secret: secret[:],
			}
			var pubkey [32]byte
			copy(pubkey[:], privkey[32:])
			dec, nym, err := mixcrypt.ReceiveFromMix(receiveTemplate,
				util.MailboxAddress(&pubkey, server), message)
			if err != nil {
				return log.Error(err)
			}
			if !bytes.Equal(nym, cipher.SHA256([]byte(myID))) {
				// discard message
				log.Warnf("ctrlengine: hashed nym does not match %s -> discard message", myID)
				if err := ce.msgDB.DelInQueue(iqIdx); err != nil {
					return err
				}
			} else {
				log.Info("envelope successfully decrypted")
				err := ce.msgDB.SetInQueue(iqIdx, base64.Encode(dec))
				if err != nil {
					return err
				}
			}
		} else {
			log.Debugf("decrypt message (iqIdx=%d)", iqIdx)
			senderID, plainMsg, err := mutecryptDecrypt(c, ce.passphrase,
				[]byte(msg), ce.fileTable.StatusFP)
			if err != nil {
				return err
			}
			if senderID == "" {
				// message could not be decrypted, but we do not want to fail
				if err := ce.msgDB.DelInQueue(iqIdx); err != nil {
					return err
				}
				continue
			}
			// check if contact exists
			contact, _, contactType, err := ce.msgDB.GetContact(myID, senderID)
			if err != nil {
				return log.Error(err)
			}
			// TODO: we do not have to do request UID message from server
			// here, but we should use the one contained in the message and
			// compare it with hash chain entry (doesn't compromise anonymity)
			var drop bool
			if contact == "" {
				err := ce.contactAdd(myID, senderID, "", host, msgdb.GrayList, c)
				if err != nil {
					return log.Error(err)
				}
			} else if contactType == msgdb.BlackList {
				// messages from black listed contacts are dropped directly
				log.Debug("message from black listed contact dropped")
				drop = true
			}
			err = ce.msgDB.RemoveInQueue(iqIdx, plainMsg, senderID, drop)
			if err != nil {
				return err
			}
		}
	}
	return nil
}
Пример #17
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
}