// getOrRequestPublicIdentity retrieves the needed public identity from bmd // or sends a getpubkey request if it doesn't exist in its database. If both // return types are nil, it means a getpubkey request has been queued. func (s *server) getOrRequestPublicIdentity(user uint32, address string) (*identity.Public, error) { serverLog.Debug("getOrRequestPublicIdentity called for ", address) id, err := s.bmd.GetIdentity(address) if err == nil { return id, nil } else if err != rpc.ErrIdentityNotFound { return nil, err } addr, err := bmutil.DecodeAddress(address) if err != nil { return nil, fmt.Errorf("Failed to decode address: %v", err) } serverLog.Debug("getOrRequestPublicIdentity: address not found, send pubkey request.") // We don't have the identity so craft a getpubkey request. var tag wire.ShaHash copy(tag[:], addr.Tag()) msg := obj.NewGetPubKey(0, time.Now().Add(defaultGetpubkeyExpiry), addr.Version, addr.Stream, (*wire.RipeHash)(&addr.Ripe), &tag) // Enqueue the request for proof-of-work. b := wire.EncodeMessage(msg.MsgObject())[8:] // exclude nonce target := pow.CalculateTarget(uint64(len(b)), uint64(msg.Header().Expiration().Sub(time.Now()).Seconds()), pow.DefaultData) s.pow.Run(target, b, func(nonce pow.Nonce) { err := s.Send(append(nonce.Bytes(), b...)) if err != nil { serverLog.Error("Could not run pow: ", err) } // Store a record of the public key request. count, _ := s.pk.New(address) serverLog.Tracef("getOrRequestPublicIdentity: Requested address %s %d time(s).", address, count) }) return nil, nil }
// trySend takes a Bitmessage and does whatever needs to be done to it // next in order to send it into the network. There are some steps in this // process that take a bit of time, so they can't all be handled sequentially // by one function. If we don't have the recipient's private key yet, we // can't send the message and we have to send a pubkey request to him instead. // On the other hand, messages might come in for which we already have the // public key and then we can go on to the next step right away. // // The next step is proof-of-work, and that also takes time. func (u *User) trySend(bmsg *Bmail) error { outbox := u.boxes[OutboxFolderName] // First we attempt to generate the wire.Object form of the message. // If we can't, then it is possible that we don't have the recipient's // pubkey. That is not an error state. If no object and no error is // returned, this is what has happened. If there is no object, then we // can't proceed futher so trySend completes. object, powData, err := bmsg.GenerateObject(u.server) if object == nil { smtpLog.Debug("trySend: could not generate message. Pubkey request sent? ", err == nil) if err == nil { bmsg.state.PubkeyRequestOutstanding = true err := outbox.saveBitmessage(bmsg) if err != nil { return err } return nil } return err } bmsg.state.PubkeyRequestOutstanding = false // sendPow takes a message in wire format with all required information // to send it over the network other than having proof-of-work run on it. // It generates the correct parameters for running the proof-of-work and // sends it to the proof-of-work queue with a function provided by the // user that says what to do with the completed message when the // proof-of-work is done. sendPow := func(object obj.Object, powData *pow.Data, done func([]byte)) { encoded := wire.Encode(object) q := encoded[8:] // exclude the nonce target := pow.CalculateTarget(uint64(len(q)), uint64(object.Header().Expiration().Sub(time.Now()).Seconds()), *powData) // Attempt to run pow on the message. u.server.RunPow(target, q, func(n pow.Nonce) { // Put the nonce bytes into the encoded form of the message. q = append(n.Bytes(), q...) done(q) }) } // sendPreparedMessage is used after we have looked up private keys and // generated an ack message, if applicable. sendPreparedMessage := func() error { err := outbox.saveBitmessage(bmsg) if err != nil { return err } // Put the prepared object in the pow queue and send it off // through the network. sendPow(object, powData, func(completed []byte) { err := func() error { // Save Bitmessage in outbox folder. err := u.boxes[OutboxFolderName].saveBitmessage(bmsg) if err != nil { return err } u.server.Send(completed) // Select new box for the message. var newBoxName string if bmsg.state.AckExpected { newBoxName = LimboFolderName } else { newBoxName = SentFolderName } bmsg.state.SendTries++ bmsg.state.LastSend = time.Now() return u.Move(bmsg, OutboxFolderName, newBoxName) }() // We can't return the error any further because this function // isn't even run until long after trySend completes! if err != nil { smtpLog.Error("trySend: ", err) } }) return nil } // We may desire to receive an ack with this message, which has not yet // been created. In that case, we need to do proof-of-work on the ack just // as on the entire message. if bmsg.Ack != nil && bmsg.state.AckExpected { ack, powData, err := bmsg.generateAck(u.server) if err != nil { return err } err = outbox.saveBitmessage(bmsg) if err != nil { return err } sendPow(ack, powData, func(completed []byte) { err := func() error { // Add the ack to the message. bmsg.Ack = completed return sendPreparedMessage() } // Once again, we can't return the error any further because // trySend is over by the time this function is run. if err != nil { smtpLog.Error("trySend: ", err) } }) } else { return sendPreparedMessage() } return nil }
// newGetpubkey is called when a new getpubkey is received by the RPC client. // Getpubkey requests are guaranteed to be received in ascending order of // counter value. func (s *server) newGetpubkey(counter uint64, object []byte) { // Store counter value. atomic.StoreUint64(&s.getpubkeyCounter, counter) msg := &obj.GetPubKey{} err := msg.Decode(bytes.NewReader(object)) if err != nil { serverLog.Errorf("Failed to decode getpubkey #%d from bytes: %v", counter, err) return // Ignore message. } var privID *keymgr.PrivateID header := msg.Header() // Check if the getpubkey request corresponds to any of our identities. for _, user := range s.users { err = user.Keys.ForEach(func(id *keymgr.PrivateID) error { if id.Disabled || id.IsChan { // We don't care about these. return nil } var cond bool // condition to satisfy switch header.Version { case obj.SimplePubKeyVersion, obj.ExtendedPubKeyVersion: cond = bytes.Equal(id.Private.Address.Ripe[:], msg.Ripe[:]) case obj.TagGetPubKeyVersion: cond = bytes.Equal(id.Private.Address.Tag(), msg.Tag[:]) } if cond { privID = id return errors.New("We have a match.") } return nil }) if err != nil { break } } if err == nil { return } addr := privID.Address() serverLog.Infof("Received a getpubkey request for %s, sending out the pubkey.", addr) // Generate a pubkey message. pkMsg, err := cipher.GeneratePubKey(&privID.Private, defaultPubkeyExpiry) if err != nil { serverLog.Errorf("Failed to generate pubkey for %s: %v", addr, err) return } // Add it to pow queue. pkObj := pkMsg.Object().MsgObject() pkHeader := pkObj.Header() b := wire.EncodeMessage(pkObj)[8:] // exclude nonce target := pow.CalculateTarget(uint64(len(b)), uint64(pkHeader.Expiration().Sub(time.Now()).Seconds()), pow.DefaultData) s.pow.Run(target, b, func(nonce pow.Nonce) { s.Send(append(nonce.Bytes(), b...)) }) }