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 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 }
func (ce *CtrlEngine) procOutQueue( c *cli.Context, nym string, failDelivery bool, ) error { log.Debug("procOutQueue()") for { oqIdx, msg, nymaddress, minDelay, maxDelay, envelope, err := ce.msgDB.GetOutQueue(nym) if err != nil { return err } if msg == "" { log.Debug("break") break // no more messages in outqueue } if !envelope { log.Debug("envelope") // parse nymaddress na, err := base64.Decode(nymaddress) if err != nil { return log.Error(na) } addr, err := nymaddr.ParseAddress(na) if err != nil { return err } // get token from wallet var pubkey [32]byte copy(pubkey[:], addr.TokenPubKey) token, err := wallet.GetToken(ce.client, "Message", &pubkey) if err != nil { return err } // `muteproto create` env, err := muteprotoCreate(c, msg, minDelay, maxDelay, base64.Encode(token.Token), nymaddress) if err != nil { return log.Error(err) } // update outqueue if err := ce.msgDB.SetOutQueue(oqIdx, env); err != nil { ce.client.UnlockToken(token.Hash) return err } ce.client.DelToken(token.Hash) msg = env } // `muteproto deliver` if failDelivery { return log.Error(ErrDeliveryFailed) } sendTime := times.Now() + int64(minDelay) // earliest resend, err := muteprotoDeliver(c, msg) if err != nil { // If the message delivery failed because the token expired in the // meantime we retract the message from the outqueue (setting it // back to 'ToSend') and start the delivery process for this // message all over again. // Matching the error message string is not optimal, but the best // available solution since the error results from calling another // binary (muteproto). if strings.HasSuffix(err.Error(), client.ErrFinal.Error()) { log.Debug("retract") if err := ce.msgDB.RetractOutQueue(oqIdx); err != nil { return err } continue } return log.Error(err) } if resend { // set resend status log.Debug("resend") if err := ce.msgDB.SetResendOutQueue(oqIdx); err != nil { return err } } else { // remove from outqueue log.Debug("remove") if err := ce.msgDB.RemoveOutQueue(oqIdx, sendTime); err != nil { return err } } } return nil }
func (ce *CtrlEngine) uidNew( c *cli.Context, minDelay, maxDelay int32, host string, ) error { // make sure the ID is well-formed unmapped := c.String("id") id, domain, err := identity.MapPlus(unmapped) if err != nil { return err } // sync corresponding hashchain if id != "keyserver" { if err := ce.upkeepHashchain(c, domain, c.String("host")); err != nil { return err } } // check that ID has not been registered already by the same user unmappedID, _, err := ce.msgDB.GetNym(id) if err != nil { return err } if unmappedID != "" { return log.Error(ErrUserIDOwned) } // check that ID has not been registered already by other user err = mutecryptHashchainSearch(c, id, c.String("host"), ce.passphrase) if err == nil { return log.Error(ErrUserIDTaken) } // get token from wallet token, err := wallet.GetToken(ce.client, def.AccdUsage, def.AccdOwner) if err != nil { return err } // register account for UID _, privkey, err := ed25519.GenerateKey(cipher.RandReader) if err != nil { return log.Error(err) } server, err := mixclient.PayAccount(privkey, token.Token, "", def.CACert) if err != nil { ce.client.UnlockToken(token.Hash) return log.Error(err) } ce.client.DelToken(token.Hash) // generate secret for account var secret [64]byte if _, err := io.ReadFull(cipher.RandReader, secret[:]); err != nil { return err } // get mixaddress and nymaddress for KeyInit message expire := times.ThirtyDaysLater() // TODO: make this settable singleUse := false // TODO correct? var pubkey [ed25519.PublicKeySize]byte copy(pubkey[:], privkey[32:]) mixaddress, nymaddress, err := util.NewNymAddress(domain, secret[:], expire, singleUse, minDelay, maxDelay, id, &pubkey, server, def.CACert) if err != nil { return err } // generate UID err = mutecryptNewUID(c, ce.passphrase, id, domain, host, mixaddress, nymaddress, ce.client) if err != nil { return err } // save name mapping if err := ce.msgDB.AddNym(id, unmapped, c.String("full-name")); err != nil { return err } // register account for UID err = ce.msgDB.AddAccount(id, "", privkey, server, &secret, minDelay, maxDelay) if err != nil { return err } // set active UID, if this was the first UID active, err := ce.msgDB.GetValue(msgdb.ActiveUID) if err != nil { return err } if active == "" { if err := ce.msgDB.AddValue(msgdb.ActiveUID, unmapped); err != nil { return err } } return nil }