// 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 }
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 }
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 }
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 }
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 }
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 }
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 }
// 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") } } }
// This example shows when and how to use the info log level. func Example_info() { // server receives message log.Info("server: message received") }
// 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 }
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 }
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 }
// 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 }
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 }
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 }
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 }
// 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 }