// deleteUID deletes a nym. func (ce *CryptEngine) deleteUID(pseudonym string, force bool) error { // map pseudonym id, err := identity.Map(pseudonym) if err != nil { return err } // get UID from keyDB msg, _, err := ce.keyDB.GetPrivateUID(id, false) if err != nil { return err } // ask for manual confirmation if !force { fmt.Fprintf(os.Stderr, "cryptengine: delete user ID %s and all it's key material? ", pseudonym) var response string _, err := fmt.Scanln(&response) if err != nil { return log.Error(err) } if !strings.HasPrefix(strings.ToLower(response), "y") { return log.Error("cryptengine: user ID deletion aborted") } } // delete UID from keyDB if err := ce.keyDB.DelPrivateUID(msg); err != nil { return err } return nil }
func (ce *CtrlEngine) msgRead(w io.Writer, myID string, msgID int64) error { idMapped, err := identity.Map(myID) if err != nil { return err } from, to, msg, date, err := ce.msgDB.GetMessage(idMapped, msgID) if err != nil { return err } if err := ce.msgDB.ReadMessage(msgID); err != nil { return err } subject, message := mimeMsg.SplitMessage(msg) fmt.Fprintf(w, "Date: %s\r\n", time.Unix(date, 0).UTC().Format(time.RFC1123Z)) fmt.Fprintf(w, "From: %s\r\n", from) fmt.Fprintf(w, "To: %s\r\n", to) if subject != "" { fmt.Fprintf(w, "Subject: %s\r\n", mime.QEncoding.Encode("utf-8", subject)) } fmt.Fprintf(w, "MIME-Version: 1.0\r\n") fmt.Fprintf(w, "Content-Type: text/plain; charset=UTF-8\r\n") fmt.Fprintf(w, "\r\n") fmt.Fprintf(w, "%s", message) return nil }
// encrypt reads data from r, encrypts it for identity to (with identity from // as sender), and writes it to w. func (ce *CryptEngine) encrypt( w io.Writer, from, to string, sign bool, nymAddress string, r io.Reader, statusfp *os.File, ) error { // map pseudonyms fromID, fromDomain, err := identity.MapPlus(from) if err != nil { return err } toID, err := identity.Map(to) if err != nil { return err } // get fromUID from keyDB fromUID, _, err := ce.keyDB.GetPrivateUID(fromID, true) if err != nil { return err } // get toUID from keyDB toUID, _, found, err := ce.keyDB.GetPublicUID(toID, math.MaxInt64) // TODO: use simpler API if err != nil { return err } if !found { return log.Errorf("not UID for '%s' found", toID) } // encrypt message senderLastKeychainHash, err := ce.keyDB.GetLastHashChainEntry(fromDomain) if err != nil { return err } var privateSigKey *[64]byte if sign { privateSigKey = fromUID.PrivateSigKey64() } args := &msg.EncryptArgs{ Writer: w, From: fromUID, To: toUID, NymAddress: nymAddress, SenderLastKeychainHash: senderLastKeychainHash, PrivateSigKey: privateSigKey, Reader: r, Rand: cipher.RandReader, KeyStore: ce, } nymAddress, err = msg.Encrypt(args) if err != nil { return err } // show nymaddress on status-fd fmt.Fprintf(statusfp, "NYMADDRESS:\t%s\n", nymAddress) return nil }
func (ce *CtrlEngine) msgDelete(myID string, msgID int64) error { idMapped, err := identity.Map(myID) if err != nil { return err } if err := ce.msgDB.DelMessage(idMapped, msgID); err != nil { return err } return nil }
func (ce *CtrlEngine) uidSwitch(unmappedID string) error { mappedID, err := identity.Map(unmappedID) if err != nil { return err } existing, _, err := ce.msgDB.GetNym(mappedID) if err != nil { return err } if existing == "" { return log.Errorf("user ID %s unknown", unmappedID) } if err := ce.msgDB.AddValue(msgdb.ActiveUID, mappedID); err != nil { return err } return nil }
func (ce *CtrlEngine) uidEdit(unmappedID, fullName string) error { mappedID, err := identity.Map(unmappedID) if err != nil { return err } old, _, err := ce.msgDB.GetNym(mappedID) if err != nil { return err } if old == "" { return log.Errorf("user ID %s unknown", unmappedID) } if err := ce.msgDB.AddNym(mappedID, unmappedID, fullName); err != nil { return err } return nil }
// AddContact adds or updates a contact in msgDB. func (msgDB *MsgDB) AddContact( myID, mappedID, unmappedID, fullName string, contactType ContactType, ) error { if err := identity.IsMapped(myID); err != nil { return log.Error(err) } if err := identity.IsMapped(mappedID); err != nil { return log.Error(err) } if unmappedID == "" { return log.Error("msgdb: unmappedID must be defined") } // make sure mappedID and unmappedID fit together mID, err := identity.Map(unmappedID) if err != nil { return log.Error(err) } if mID != mappedID { return log.Errorf("msgdb: identity.Map(%s) != %s", unmappedID, mappedID) } // get MyID var uid int if err := msgDB.getNymUIDQuery.QueryRow(myID).Scan(&uid); err != nil { return log.Error(err) } // add contact res, err := msgDB.updateContactQuery.Exec(unmappedID, fullName, contactType, uid, mappedID) if err != nil { return log.Error(err) } nRows, err := res.RowsAffected() if err != nil { return log.Error(err) } if nRows == 0 { _, err := msgDB.insertContactQuery.Exec(uid, mappedID, unmappedID, fullName, contactType) if err != nil { return log.Error(err) } } return nil }
func (ce *CtrlEngine) msgList(w io.Writer, id string) error { idMapped, err := identity.Map(id) if err != nil { return err } ids, err := ce.msgDB.GetMsgIDs(idMapped) if err != nil { return err } for _, id := range ids { var ( direction rune status rune ) if id.Incoming { direction = '>' if id.Read { status = 'R' } else { status = 'N' } } else { direction = '<' if id.Sent { status = 'S' } else { status = 'P' } } fmt.Fprintf(w, "%c%c %d\t%s\t%s\t%s\t%s\n", direction, status, id.MsgID, time.Unix(id.Date, 0).Format(time.RFC3339), id.From, id.To, id.Subject) } return nil }
// genupdate generates an update for the (registered) nym and stores it in keydb. func (ce *CryptEngine) genupdate(pseudonym string) error { // map pseudonym id, err := identity.Map(pseudonym) if err != nil { return err } // get old UID from keyDB oldUID, _, err := ce.keyDB.GetPrivateUID(id, true) if err != nil { return err } // generate new UID newUID, err := oldUID.Update(cipher.RandReader) if err != nil { return err } // store new UID in keyDB if err := ce.keyDB.AddPrivateUID(newUID); err != nil { return 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 }
// AddNym adds or updates a mapping from a mapped ID to an unmapped ID and // full name. func (msgDB *MsgDB) AddNym(mappedID, unmappedID, fullName string) error { if mappedID == "" { return log.Error("msgdb: mappedID must be defined") } if unmappedID == "" { return log.Error("msgdb: unmappedID must be defined") } // make sure the mappedID is mapped if err := identity.IsMapped(mappedID); err != nil { return log.Error(err) } // make sure mappedID and unmappedID fit together mID, err := identity.Map(unmappedID) if err != nil { return log.Error(err) } if mID != mappedID { return log.Errorf("msgdb: identity.Map(%s) != %s", unmappedID, mappedID) } // fullName can be empty res, err := msgDB.updateNymQuery.Exec(unmappedID, fullName, mappedID) if err != nil { return log.Error(err) } nRows, err := res.RowsAffected() if err != nil { return log.Error(err) } if nRows == 0 { _, err := msgDB.insertNymQuery.Exec(mappedID, unmappedID, fullName) if err != nil { return log.Error(err) } } return nil }
func (ce *CtrlEngine) getNyms(id string, all bool) ([]string, error) { var nyms []string if all { ids, err := ce.msgDB.GetNyms(true) if err != nil { return nil, err } nyms = append(nyms, ids...) } else { idMapped, err := identity.Map(id) if err != nil { return nil, err } prev, _, err := ce.msgDB.GetNym(idMapped) if err != nil { return nil, err } if prev == "" { return nil, log.Errorf("user ID %s not found", id) } nyms = append(nyms, idMapped) } return nyms, 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) 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 }
func (ce *CtrlEngine) uidDelete( c *cli.Context, unmappedID string, force bool, statfp io.Writer, ) error { mappedID, err := identity.Map(unmappedID) if err != nil { return err } // make sure user ID is in message DB prev, _, err := ce.msgDB.GetNym(mappedID) if err != nil { return err } if prev == "" { return log.Errorf("ctrlengine: user ID '%s' unknown", unmappedID) } // ask for manual confirmation if !force { fmt.Fprintf(statfp, "ctrlengine: delete user ID %s and all contacts and messages? ", unmappedID) var response string _, err := fmt.Scanln(&response) if err != nil { return log.Error(err) } if !strings.HasPrefix(strings.ToLower(response), "y") { return log.Error("ctrlengine: user ID deletion aborted") } } // get account information before deletion contacts, err := ce.msgDB.GetAccounts(mappedID) if err != nil { return err } var privkeys []*[ed25519.PrivateKeySize]byte var servers []string for _, contact := range contacts { privkey, server, _, _, _, _, err := ce.msgDB.GetAccount(mappedID, contact) if err != nil { return err } privkeys = append(privkeys, privkey) servers = append(servers, server) } // remove user ID from message DB if err := ce.msgDB.DelNym(mappedID); err != nil { return err } // remove user ID from key DB if err := mutecryptDeleteUID(c, mappedID, ce.passphrase); err != nil { return err } // delete corresponding accounts. It doesn't matter that much, if this // fails because the accounts will expiry eventually. for i, privkey := range privkeys { err := mixclient.DeleteAccount(privkey, servers[i], def.CACert) if err != nil { return log.Error(err) } } return nil }