From 18ff2ad5f47e4b2e898db7904672fb35a771d844 Mon Sep 17 00:00:00 2001 From: Vlad Date: Fri, 23 Sep 2016 16:38:33 +0200 Subject: [PATCH] whisper: fixed PR according to request of @fjl --- cmd/gethrpctest/main.go | 2 +- cmd/utils/flags.go | 2 +- whisper/{whisper05 => shhapi}/api.go | 129 +++++++++------- whisper/{whisper02 => whisperv2}/api.go | 2 +- whisper/{whisper02 => whisperv2}/doc.go | 2 +- whisper/{whisper02 => whisperv2}/envelope.go | 2 +- .../{whisper02 => whisperv2}/envelope_test.go | 2 +- whisper/{whisper02 => whisperv2}/filter.go | 2 +- .../{whisper02 => whisperv2}/filter_test.go | 2 +- whisper/{whisper02 => whisperv2}/main.go | 0 whisper/{whisper02 => whisperv2}/message.go | 2 +- .../{whisper02 => whisperv2}/message_test.go | 2 +- whisper/{whisper02 => whisperv2}/peer.go | 2 +- whisper/{whisper02 => whisperv2}/peer_test.go | 2 +- whisper/{whisper02 => whisperv2}/topic.go | 2 +- .../{whisper02 => whisperv2}/topic_test.go | 2 +- whisper/{whisper02 => whisperv2}/whisper.go | 2 +- .../{whisper02 => whisperv2}/whisper_test.go | 2 +- whisper/{whisper05 => whisperv5}/doc.go | 36 ++--- whisper/{whisper05 => whisperv5}/envelope.go | 17 +- whisper/{whisper05 => whisperv5}/filter.go | 38 +++-- whisper/{whisper05 => whisperv5}/message.go | 67 ++++---- whisper/{whisper05 => whisperv5}/peer.go | 30 ++-- whisper/{whisper05 => whisperv5}/topic.go | 16 +- whisper/{whisper05 => whisperv5}/whisper.go | 146 +++++++----------- 25 files changed, 250 insertions(+), 261 deletions(-) rename whisper/{whisper05 => shhapi}/api.go (80%) rename whisper/{whisper02 => whisperv2}/api.go (99%) rename whisper/{whisper02 => whisperv2}/doc.go (98%) rename whisper/{whisper02 => whisperv2}/envelope.go (99%) rename whisper/{whisper02 => whisperv2}/envelope_test.go (99%) rename whisper/{whisper02 => whisperv2}/filter.go (99%) rename whisper/{whisper02 => whisperv2}/filter_test.go (99%) rename whisper/{whisper02 => whisperv2}/main.go (100%) rename whisper/{whisper02 => whisperv2}/message.go (99%) rename whisper/{whisper02 => whisperv2}/message_test.go (99%) rename whisper/{whisper02 => whisperv2}/peer.go (99%) rename whisper/{whisper02 => whisperv2}/peer_test.go (99%) rename whisper/{whisper02 => whisperv2}/topic.go (99%) rename whisper/{whisper02 => whisperv2}/topic_test.go (99%) rename whisper/{whisper02 => whisperv2}/whisper.go (99%) rename whisper/{whisper02 => whisperv2}/whisper_test.go (99%) rename whisper/{whisper05 => whisperv5}/doc.go (78%) rename whisper/{whisper05 => whisperv5}/envelope.go (95%) rename whisper/{whisper05 => whisperv5}/filter.go (85%) rename whisper/{whisper05 => whisperv5}/message.go (91%) rename whisper/{whisper05 => whisperv5}/peer.go (89%) rename whisper/{whisper05 => whisperv5}/topic.go (85%) rename whisper/{whisper05 => whisperv5}/whisper.go (84%) diff --git a/cmd/gethrpctest/main.go b/cmd/gethrpctest/main.go index 5e2b9cde3d..aee372fb4c 100644 --- a/cmd/gethrpctest/main.go +++ b/cmd/gethrpctest/main.go @@ -32,7 +32,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/tests" - whisper "github.com/ethereum/go-ethereum/whisper/whisper02" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" ) const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 95d89bb33b..0d016c3116 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -48,7 +48,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/rpc" - whisper "github.com/ethereum/go-ethereum/whisper/whisper02" + whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" "gopkg.in/urfave/cli.v1" ) diff --git a/whisper/whisper05/api.go b/whisper/shhapi/api.go similarity index 80% rename from whisper/whisper05/api.go rename to whisper/shhapi/api.go index 928cdcb31a..3b485a7191 100644 --- a/whisper/whisper05/api.go +++ b/whisper/shhapi/api.go @@ -14,32 +14,53 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper05 +package shhapi import ( "encoding/json" "errors" "fmt" + mathrand "math/rand" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/rpc" - - mathrand "math/rand" + "github.com/ethereum/go-ethereum/whisper/whisperv5" ) +type WhisperOfflineError struct{} + +var whisperOffLineErr = new(WhisperOfflineError) + +func (e *WhisperOfflineError) Error() string { + return "whisper is offline" +} + // PublicWhisperAPI provides the whisper RPC service. type PublicWhisperAPI struct { - whisper *Whisper + whisper *whisperv5.Whisper } // NewPublicWhisperAPI create a new RPC whisper service. -func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI { +func NewPublicWhisperAPI() *PublicWhisperAPI { + w := whisperv5.New(nil) return &PublicWhisperAPI{whisper: w} } +// APIs returns the RPC descriptors the Whisper implementation offers +func APIs() []rpc.API { + return []rpc.API{ + { + Namespace: whisperv5.ProtocolName, + Version: whisperv5.ProtocolVersionStr, + Service: NewPublicWhisperAPI(), + Public: true, + }, + } +} + // Version returns the Whisper version this node offers. func (self *PublicWhisperAPI) Version() (*rpc.HexNumber, error) { if self.whisper == nil { @@ -54,7 +75,7 @@ func (self *PublicWhisperAPI) MarkPeerTrusted(peerID *rpc.HexBytes) error { if self.whisper == nil { return whisperOffLineErr } - return self.whisper.MarkPeerTrusted(peerID) + return self.whisper.MarkPeerTrusted(*peerID) } // RequestHistoricMessages requests the peer to deliver the old (expired) messages. @@ -65,7 +86,7 @@ func (self *PublicWhisperAPI) RequestHistoricMessages(peerID *rpc.HexBytes, data if self.whisper == nil { return whisperOffLineErr } - return self.whisper.RequestHistoricMessages(peerID, data) + return self.whisper.RequestHistoricMessages(*peerID, *data) } // HasIdentity checks if the the whisper node is configured with the private key @@ -134,13 +155,13 @@ func (self *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (*rpc.HexNumber, return nil, whisperOffLineErr } - filter := Filter{ + filter := whisperv5.Filter{ Src: crypto.ToECDSAPub(args.From), Dst: crypto.ToECDSAPub(args.To), KeySym: self.whisper.GetTopicKey(args.KeyName), PoW: args.PoW, - messages: make(map[common.Hash]*ReceivedMessage), - acceptP2P: args.AcceptP2P, + Messages: make(map[common.Hash]*whisperv5.ReceivedMessage), + AcceptP2P: args.AcceptP2P, } if len(filter.KeySym) > 0 { @@ -176,7 +197,7 @@ func (self *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (*rpc.HexNumber, } if len(args.To) > 0 { - if !validatePublicKey(filter.Dst) { + if !whisperv5.ValidatePublicKey(filter.Dst) { info := "NewFilter: Invalid 'To' address" glog.V(logger.Error).Infof(info) return nil, errors.New(info) @@ -190,7 +211,7 @@ func (self *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (*rpc.HexNumber, } if len(args.From) > 0 { - if !validatePublicKey(filter.Src) { + if !whisperv5.ValidatePublicKey(filter.Src) { info := "NewFilter: Invalid 'From' address" glog.V(logger.Error).Infof(info) return nil, errors.New(info) @@ -208,9 +229,9 @@ func (self *PublicWhisperAPI) UninstallFilter(filterId rpc.HexNumber) { // GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval. func (self *PublicWhisperAPI) GetFilterChanges(filterId rpc.HexNumber) []WhisperMessage { - f := self.whisper.filters.Get(filterId.Int()) + f := self.whisper.GetFilter(filterId.Int()) if f != nil { - newMail := f.retrieve() + newMail := f.Retrieve() return toWhisperMessages(newMail) } return toWhisperMessages(nil) @@ -223,7 +244,7 @@ func (self *PublicWhisperAPI) GetMessages(filterId rpc.HexNumber) []WhisperMessa } // toWhisperMessages converts a Whisper message to a RPC whisper message. -func toWhisperMessages(messages []*ReceivedMessage) []WhisperMessage { +func toWhisperMessages(messages []*whisperv5.ReceivedMessage) []WhisperMessage { msgs := make([]WhisperMessage, len(messages)) for i, msg := range messages { msgs[i] = NewWhisperMessage(msg) @@ -237,7 +258,7 @@ func (self *PublicWhisperAPI) Post(args PostArgs) error { return whisperOffLineErr } - params := MessageParams{ + params := whisperv5.MessageParams{ TTL: args.TTL, Dst: crypto.ToECDSAPub(args.To), KeySym: self.whisper.GetTopicKey(args.KeyName), @@ -250,7 +271,7 @@ func (self *PublicWhisperAPI) Post(args PostArgs) error { if len(args.From) > 0 { pub := crypto.ToECDSAPub(args.From) - if !validatePublicKey(pub) { + if !whisperv5.ValidatePublicKey(pub) { info := "Post: Invalid 'From' address" glog.V(logger.Error).Infof(info) return errors.New(info) @@ -263,7 +284,7 @@ func (self *PublicWhisperAPI) Post(args PostArgs) error { } } - filter := self.whisper.filters.Get(args.FilterID) + filter := self.whisper.GetFilter(args.FilterID) if filter == nil && args.FilterID > -1 { info := fmt.Sprintf("Post: wrong filter id %d", args.FilterID) glog.V(logger.Error).Infof(info) @@ -281,7 +302,7 @@ func (self *PublicWhisperAPI) Post(args PostArgs) error { if params.Src == nil && filter.Src != nil { params.Src = filter.KeyAsym } - if (params.Topic == TopicType{}) { + if (params.Topic == whisperv5.TopicType{}) { sz := len(filter.Topics) if sz < 1 { info := fmt.Sprintf("Post: no topics in filter # %d", args.FilterID) @@ -317,7 +338,7 @@ func (self *PublicWhisperAPI) Post(args PostArgs) error { } if len(args.To) > 0 { - if !validatePublicKey(params.Dst) { + if !whisperv5.ValidatePublicKey(params.Dst) { info := "Post: Invalid 'To' address" glog.V(logger.Error).Infof(info) return errors.New(info) @@ -325,57 +346,57 @@ func (self *PublicWhisperAPI) Post(args PostArgs) error { } // encrypt and send - message := NewSentMessage(¶ms) + message := whisperv5.NewSentMessage(¶ms) envelope, err := message.Wrap(params) if err != nil { glog.V(logger.Error).Infof(err.Error()) return err } - if len(envelope.Data) > msgMaxLength { + if len(envelope.Data) > whisperv5.MaxMessageLength { info := "Post: message is too big" glog.V(logger.Error).Infof(info) return errors.New(info) } - if (envelope.Topic == TopicType{} && envelope.isSymmetric()) { + if (envelope.Topic == whisperv5.TopicType{} && envelope.IsSymmetric()) { info := "Post: topic is missing for symmetric encryption" glog.V(logger.Error).Infof(info) return errors.New(info) } - if args.Peer != nil { - return self.whisper.SendP2PMessage(&args.Peer, envelope) + if args.PeerID != nil { + return self.whisper.SendP2PMessage(args.PeerID, envelope) } return self.whisper.Send(envelope) } type PostArgs struct { - TTL uint32 `json:"ttl"` - From rpc.HexBytes `json:"from"` - To rpc.HexBytes `json:"to"` - KeyName string `json:"keyname"` - Topic TopicType `json:"topic"` - Padding rpc.HexBytes `json:"padding"` - Payload rpc.HexBytes `json:"payload"` - WorkTime uint32 `json:"worktime"` - PoW float64 `json:"pow"` - FilterID int `json:"filter"` - Peer rpc.HexBytes `json:"directP2P"` + TTL uint32 `json:"ttl"` + From rpc.HexBytes `json:"from"` + To rpc.HexBytes `json:"to"` + KeyName string `json:"keyname"` + Topic whisperv5.TopicType `json:"topic"` + Padding rpc.HexBytes `json:"padding"` + Payload rpc.HexBytes `json:"payload"` + WorkTime uint32 `json:"worktime"` + PoW float64 `json:"pow"` + FilterID int `json:"filter"` + PeerID rpc.HexBytes `json:"directP2P"` } func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { var obj struct { - TTL uint32 `json:"ttl"` - From rpc.HexBytes `json:"from"` - To rpc.HexBytes `json:"to"` - KeyName string `json:"keyname"` - Topic TopicType `json:"topic"` - Payload rpc.HexBytes `json:"payload"` - Padding rpc.HexBytes `json:"padding"` - WorkTime uint32 `json:"worktime"` - PoW float64 `json:"pow"` - FilterID rpc.HexBytes `json:"filter"` - Peer rpc.HexBytes `json:"directP2P"` + TTL uint32 `json:"ttl"` + From rpc.HexBytes `json:"from"` + To rpc.HexBytes `json:"to"` + KeyName string `json:"keyname"` + Topic whisperv5.TopicType `json:"topic"` + Payload rpc.HexBytes `json:"payload"` + Padding rpc.HexBytes `json:"padding"` + WorkTime uint32 `json:"worktime"` + PoW float64 `json:"pow"` + FilterID rpc.HexBytes `json:"filter"` + PeerID rpc.HexBytes `json:"directP2P"` } if err := json.Unmarshal(data, &obj); err != nil { @@ -392,10 +413,10 @@ func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { args.WorkTime = obj.WorkTime args.PoW = obj.PoW args.FilterID = -1 - args.Peer = obj.Peer + args.PeerID = obj.PeerID if obj.FilterID != nil { - x := bytesToIntBigEndian(obj.FilterID) + x := whisperv5.BytesToIntBigEndian(obj.FilterID) args.FilterID = int(x) } @@ -407,7 +428,7 @@ type WhisperFilterArgs struct { From []byte KeyName string PoW float64 - Topics []TopicType + Topics []whisperv5.TopicType AcceptP2P bool } @@ -446,13 +467,13 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) { return fmt.Errorf("topic[%d] is not a string", i) } } - topicsDecoded := make([]TopicType, len(topics)) + topicsDecoded := make([]whisperv5.TopicType, len(topics)) for j, s := range topics { x := common.FromHex(s) - if x == nil || len(x) != topicLength { + if x == nil || len(x) != whisperv5.TopicLength { return fmt.Errorf("topic[%d] is invalid", j) } - topicsDecoded[j] = BytesToTopic(x) + topicsDecoded[j] = whisperv5.BytesToTopic(x) } args.Topics = topicsDecoded } @@ -473,7 +494,7 @@ type WhisperMessage struct { } // NewWhisperMessage converts an internal message into an API version. -func NewWhisperMessage(message *ReceivedMessage) WhisperMessage { +func NewWhisperMessage(message *whisperv5.ReceivedMessage) WhisperMessage { return WhisperMessage{ Payload: common.ToHex(message.Payload), Padding: common.ToHex(message.Padding), diff --git a/whisper/whisper02/api.go b/whisper/whisperv2/api.go similarity index 99% rename from whisper/whisper02/api.go rename to whisper/whisperv2/api.go index e1b28468d9..9c9c6a84c3 100644 --- a/whisper/whisper02/api.go +++ b/whisper/whisperv2/api.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "encoding/json" diff --git a/whisper/whisper02/doc.go b/whisper/whisperv2/doc.go similarity index 98% rename from whisper/whisper02/doc.go rename to whisper/whisperv2/doc.go index d2603650c7..7252f44b10 100644 --- a/whisper/whisper02/doc.go +++ b/whisper/whisperv2/doc.go @@ -29,4 +29,4 @@ Whisper is a pure identity-based messaging system. Whisper provides a low-level or prejudiced by the low-level hardware attributes and characteristics, particularly the notion of singular endpoints. */ -package whisper02 +package whisperv2 diff --git a/whisper/whisper02/envelope.go b/whisper/whisperv2/envelope.go similarity index 99% rename from whisper/whisper02/envelope.go rename to whisper/whisperv2/envelope.go index b1d74c9d61..7110ab4571 100644 --- a/whisper/whisper02/envelope.go +++ b/whisper/whisperv2/envelope.go @@ -17,7 +17,7 @@ // Contains the Whisper protocol Envelope element. For formal details please see // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes. -package whisper02 +package whisperv2 import ( "crypto/ecdsa" diff --git a/whisper/whisper02/envelope_test.go b/whisper/whisperv2/envelope_test.go similarity index 99% rename from whisper/whisper02/envelope_test.go rename to whisper/whisperv2/envelope_test.go index c7172024f7..75e2fbe8a6 100644 --- a/whisper/whisper02/envelope_test.go +++ b/whisper/whisperv2/envelope_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "bytes" diff --git a/whisper/whisper02/filter.go b/whisper/whisperv2/filter.go similarity index 99% rename from whisper/whisper02/filter.go rename to whisper/whisperv2/filter.go index 5a2108fa6d..8ce4a54fb4 100644 --- a/whisper/whisper02/filter.go +++ b/whisper/whisperv2/filter.go @@ -16,7 +16,7 @@ // Contains the message filter for fine grained subscriptions. -package whisper02 +package whisperv2 import ( "crypto/ecdsa" diff --git a/whisper/whisper02/filter_test.go b/whisper/whisperv2/filter_test.go similarity index 99% rename from whisper/whisper02/filter_test.go rename to whisper/whisperv2/filter_test.go index 7bbaa328f6..5a14a84bbd 100644 --- a/whisper/whisper02/filter_test.go +++ b/whisper/whisperv2/filter_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "bytes" diff --git a/whisper/whisper02/main.go b/whisper/whisperv2/main.go similarity index 100% rename from whisper/whisper02/main.go rename to whisper/whisperv2/main.go diff --git a/whisper/whisper02/message.go b/whisper/whisperv2/message.go similarity index 99% rename from whisper/whisper02/message.go rename to whisper/whisperv2/message.go index a3f59a690e..7ef9d0912a 100644 --- a/whisper/whisper02/message.go +++ b/whisper/whisperv2/message.go @@ -17,7 +17,7 @@ // Contains the Whisper protocol Message element. For formal details please see // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages. -package whisper02 +package whisperv2 import ( "crypto/ecdsa" diff --git a/whisper/whisper02/message_test.go b/whisper/whisperv2/message_test.go similarity index 99% rename from whisper/whisper02/message_test.go rename to whisper/whisperv2/message_test.go index e87238d0b7..efa64e431a 100644 --- a/whisper/whisper02/message_test.go +++ b/whisper/whisperv2/message_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "bytes" diff --git a/whisper/whisper02/peer.go b/whisper/whisperv2/peer.go similarity index 99% rename from whisper/whisper02/peer.go rename to whisper/whisperv2/peer.go index 3e108816d3..404ebd513e 100644 --- a/whisper/whisper02/peer.go +++ b/whisper/whisperv2/peer.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "fmt" diff --git a/whisper/whisper02/peer_test.go b/whisper/whisperv2/peer_test.go similarity index 99% rename from whisper/whisper02/peer_test.go rename to whisper/whisperv2/peer_test.go index 2ec7a51c15..9755e134c4 100644 --- a/whisper/whisper02/peer_test.go +++ b/whisper/whisperv2/peer_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "testing" diff --git a/whisper/whisper02/topic.go b/whisper/whisperv2/topic.go similarity index 99% rename from whisper/whisper02/topic.go rename to whisper/whisperv2/topic.go index 2a80df4884..3e2b47bd3f 100644 --- a/whisper/whisper02/topic.go +++ b/whisper/whisperv2/topic.go @@ -17,7 +17,7 @@ // Contains the Whisper protocol Topic element. For formal details please see // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#topics. -package whisper02 +package whisperv2 import "github.com/ethereum/go-ethereum/crypto" diff --git a/whisper/whisper02/topic_test.go b/whisper/whisperv2/topic_test.go similarity index 99% rename from whisper/whisper02/topic_test.go rename to whisper/whisperv2/topic_test.go index 21f5e55b01..efd4a2c61b 100644 --- a/whisper/whisper02/topic_test.go +++ b/whisper/whisperv2/topic_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "bytes" diff --git a/whisper/whisper02/whisper.go b/whisper/whisperv2/whisper.go similarity index 99% rename from whisper/whisper02/whisper.go rename to whisper/whisperv2/whisper.go index f0f38f29ab..d9054959e5 100644 --- a/whisper/whisper02/whisper.go +++ b/whisper/whisperv2/whisper.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "crypto/ecdsa" diff --git a/whisper/whisper02/whisper_test.go b/whisper/whisperv2/whisper_test.go similarity index 99% rename from whisper/whisper02/whisper_test.go rename to whisper/whisperv2/whisper_test.go index 42e2935732..1e0d3f85d4 100644 --- a/whisper/whisper02/whisper_test.go +++ b/whisper/whisperv2/whisper_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper02 +package whisperv2 import ( "testing" diff --git a/whisper/whisper05/doc.go b/whisper/whisperv5/doc.go similarity index 78% rename from whisper/whisper05/doc.go rename to whisper/whisperv5/doc.go index 5100a84024..6b9a0a60e5 100644 --- a/whisper/whisper05/doc.go +++ b/whisper/whisperv5/doc.go @@ -29,31 +29,35 @@ Whisper is a pure identity-based messaging system. Whisper provides a low-level or prejudiced by the low-level hardware attributes and characteristics, particularly the notion of singular endpoints. */ -package whisper05 +package whisperv5 import ( + "fmt" "time" ) const ( EnvelopeVersion = uint64(0) - protocolVersion = uint64(5) - protocolVersionStr = "5.0" - protocolName = "shh" + ProtocolVersion = uint64(5) + ProtocolVersionStr = "5.0" + ProtocolName = "shh" - statusCode = 0 - messagesCode = 1 - p2pCode = 2 - mailRequestCode = 3 + statusCode = 0 + messagesCode = 1 + p2pCode = 2 + mailRequestCode = 3 + NumberOfMessageCodes = 4 paddingMask = byte(3) signatureFlag = byte(4) - topicLength = 4 + TopicLength = 4 signatureLength = 65 aesKeyLength = 32 saltLength = 12 - msgMaxLength = 0xFFFF + + MaxMessageLength = 0xFFFF // todo: remove this restriction after testing in morden and analizing stats. this should be regulated by MinimumPoW. + MinimumPoW = 50.0 // todo: review padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility @@ -63,16 +67,12 @@ const ( DefaultTTL = 50 // seconds SynchAllowance = 10 // seconds - - MinimumPoW = 50.0 // todo: review ) -type whisperOfflineError struct{} +type unknownVersionError uint64 -var whisperOffLineErr = new(whisperOfflineError) - -func (e *whisperOfflineError) Error() string { - return "whisper is offline" +func (e unknownVersionError) Error() string { + return fmt.Sprintf("invalid envelope version %d", uint64(e)) } // MailServer represents a mail server, capable of @@ -83,5 +83,5 @@ func (e *whisperOfflineError) Error() string { // in order to bypass the expiry checks. type MailServer interface { Archive(env *Envelope) - DeliverMail(whisperPeer *WhisperPeer, data []byte) + DeliverMail(whisperPeer *Peer, data []byte) } diff --git a/whisper/whisper05/envelope.go b/whisper/whisperv5/envelope.go similarity index 95% rename from whisper/whisper05/envelope.go rename to whisper/whisperv5/envelope.go index be228adf9b..8aeab1c774 100644 --- a/whisper/whisper05/envelope.go +++ b/whisper/whisperv5/envelope.go @@ -17,7 +17,7 @@ // Contains the Whisper protocol Envelope element. For formal details please see // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes. -package whisper05 +package whisperv5 import ( "crypto/ecdsa" @@ -62,20 +62,21 @@ func NewEnvelope(ttl uint32, topic TopicType, salt []byte, aesNonce []byte, msg EnvNonce: 0, } - if EnvelopeVersion > 255 { - panic("please fix Envelope.Version size before releasing this version") + if EnvelopeVersion < 256 { + env.Version[0] = byte(EnvelopeVersion) + } else { + panic("please increase the size of Envelope.Version before releasing this version") } - env.Version[0] = byte(EnvelopeVersion) return &env } -func (self *Envelope) isSymmetric() bool { +func (self *Envelope) IsSymmetric() bool { return self.AESNonce != nil } func (self *Envelope) isAsymmetric() bool { - return !self.isSymmetric() + return !self.IsSymmetric() } func (self *Envelope) Ver() uint64 { @@ -194,7 +195,7 @@ func (self *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error if err != nil { msg = nil } - return + return msg, err } // Open tries to decrypt an envelope, and populates the message fields in case of success. @@ -204,7 +205,7 @@ func (self *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { if msg != nil { msg.Dst = watcher.Dst } - } else if self.isSymmetric() { + } else if self.IsSymmetric() { msg, _ = self.OpenSymmetric(watcher.KeySym) if msg != nil { msg.TopicKeyHash = crypto.Keccak256Hash(watcher.KeySym) diff --git a/whisper/whisper05/filter.go b/whisper/whisperv5/filter.go similarity index 85% rename from whisper/whisper05/filter.go rename to whisper/whisperv5/filter.go index fbc4f422ea..e7d77fdb92 100644 --- a/whisper/whisper05/filter.go +++ b/whisper/whisperv5/filter.go @@ -14,11 +14,10 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper05 +package whisperv5 import ( "crypto/ecdsa" - "sync" "github.com/ethereum/go-ethereum/common" @@ -32,10 +31,9 @@ type Filter struct { KeySym []byte // Key associated with the Topic TopicKeyHash common.Hash // The Keccak256Hash of the symmetric key PoW float64 // Proof of work as described in the Whisper spec - acceptP2P bool // Indicates whether this filter is interested in direct peer-to-peer messages - - messages map[common.Hash]*ReceivedMessage - mutex sync.RWMutex + AcceptP2P bool // Indicates whether this filter is interested in direct peer-to-peer messages + Messages map[common.Hash]*ReceivedMessage + Mutex sync.RWMutex } type Filters struct { @@ -78,7 +76,7 @@ func (self *Filters) NotifyWatchers(env *Envelope, messageCode uint64) { self.mutex.RLock() var msg *ReceivedMessage for _, watcher := range self.watchers { - if messageCode == p2pCode && !watcher.acceptP2P { + if messageCode == p2pCode && !watcher.AcceptP2P { continue } @@ -112,23 +110,23 @@ func (self *Filter) expectsSymmetricEncryption() bool { } func (self *Filter) Trigger(msg *ReceivedMessage) { - self.mutex.Lock() - defer self.mutex.Unlock() + self.Mutex.Lock() + defer self.Mutex.Unlock() - if _, exist := self.messages[msg.EnvelopeHash]; !exist { - self.messages[msg.EnvelopeHash] = msg + if _, exist := self.Messages[msg.EnvelopeHash]; !exist { + self.Messages[msg.EnvelopeHash] = msg } } -func (self *Filter) retrieve() (all []*ReceivedMessage) { - self.mutex.Lock() - defer self.mutex.Unlock() +func (self *Filter) Retrieve() (all []*ReceivedMessage) { + self.Mutex.Lock() + defer self.Mutex.Unlock() - all = make([]*ReceivedMessage, 0, len(self.messages)) - for _, msg := range self.messages { + all = make([]*ReceivedMessage, 0, len(self.Messages)) + for _, msg := range self.Messages { all = append(all, msg) } - self.messages = make(map[common.Hash]*ReceivedMessage) // delete old messages + self.Messages = make(map[common.Hash]*ReceivedMessage) // delete old messages return all } @@ -169,7 +167,7 @@ func (self *Filter) MatchEnvelope(envelope *Envelope) bool { if self.Topics == nil { return true // wildcard } - } else if self.expectsSymmetricEncryption() && envelope.isSymmetric() { + } else if self.expectsSymmetricEncryption() && envelope.IsSymmetric() { encryptionMethodMatch = true } @@ -185,9 +183,9 @@ func (self *Filter) MatchEnvelope(envelope *Envelope) bool { } func isEqual(a, b *ecdsa.PublicKey) bool { - if !validatePublicKey(a) { + if !ValidatePublicKey(a) { return false - } else if !validatePublicKey(b) { + } else if !ValidatePublicKey(b) { return false } // the Curve is always the same, just compare the points diff --git a/whisper/whisper05/message.go b/whisper/whisperv5/message.go similarity index 91% rename from whisper/whisper05/message.go rename to whisper/whisperv5/message.go index cae3a3b9ed..fe3fe4cb0c 100644 --- a/whisper/whisper05/message.go +++ b/whisper/whisperv5/message.go @@ -18,23 +18,21 @@ // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages. // todo: fix the spec link, and move it to doc.go -package whisper05 +package whisperv5 import ( - "errors" - "fmt" - "crypto/aes" "crypto/cipher" "crypto/ecdsa" crand "crypto/rand" "crypto/sha256" + "errors" + "fmt" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" - "golang.org/x/crypto/pbkdf2" ) @@ -95,13 +93,13 @@ func (self *ReceivedMessage) isAsymmetricEncryption() bool { return self.Dst != nil } -func DeriveOneTimeKey(key []byte, salt []byte, version uint64) (derivedKey []byte, err error) { +func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) { if version == 0 { - derivedKey = pbkdf2.Key(key, salt, 16, aesKeyLength, sha256.New) + derivedKey := pbkdf2.Key(key, salt, 16, aesKeyLength, sha256.New) + return derivedKey, nil } else { - err = fmt.Errorf("DeriveKey: invalid envelope version: %d", version) + return nil, unknownVersionError(version) } - return } // NewMessage creates and initializes a non-signed, non-encrypted Whisper message. @@ -137,7 +135,7 @@ func (self *SentMessage) appendPadding(params *MessageParams) { padSize := padChunk - odd if padSize > 255 { // this algorithm is only valid if padSizeLimitUpper <= 256. - // if padSizeLimitUpper will every change, please fix the algorithm + // if padSizeLimitUpper will ever change, please fix the algorithm // (for more information see ReceivedMessage.extractPadding() function). panic("please fix the padding algorithm before releasing new version") } @@ -154,24 +152,25 @@ func (self *SentMessage) appendPadding(params *MessageParams) { // sign calculates and sets the cryptographic signature for the message, // also setting the sign flag. -func (self *SentMessage) sign(key *ecdsa.PrivateKey) (err error) { +func (self *SentMessage) sign(key *ecdsa.PrivateKey) error { if isMessageSigned(self.Raw[0]) { // this should not happen, but no reason to panic glog.V(logger.Error).Infof("Trying to sign a message which was already signed") - return + return nil } hash := crypto.Keccak256(self.Raw) signature, err := crypto.Sign(hash, key) if err != nil { self.Raw = append(self.Raw, signature...) self.Raw[0] |= signatureFlag + return err } - return + return nil } // encryptAsymmetric encrypts a message with a public key. func (self *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { - if !validatePublicKey(key) { + if !ValidatePublicKey(key) { return fmt.Errorf("Invalid public key provided for asymmetric encryption") } encrypted, err := crypto.Encrypt(key, self.Raw) @@ -185,44 +184,41 @@ func (self *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { // nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). func (self *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) { if !validateSymmetricKey(key) { - err = fmt.Errorf("encryptSymmetric: invalid key provided for symmetric encryption") - return + return nil, nil, errors.New("invalid key provided for symmetric encryption") } salt = make([]byte, saltLength) _, err = crand.Read(salt) if err != nil { - return + return nil, nil, err } else if !validateSymmetricKey(salt) { - err = fmt.Errorf("encryptSymmetric: failed to generate salt") - return + return nil, nil, errors.New("crypto/rand failed to generate salt") } derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion) if err != nil { - return + return nil, nil, err } if !validateSymmetricKey(derivedKey) { - err = fmt.Errorf("encryptSymmetric: invalid key derived") - return + return nil, nil, errors.New("failed to derive one-time key") } block, err := aes.NewCipher(derivedKey) if err != nil { - return + return nil, nil, err } aesgcm, err := cipher.NewGCM(block) if err != nil { - return + return nil, nil, err } // never use more than 2^32 random nonces with a given key nonce = make([]byte, aesgcm.NonceSize()) _, err = crand.Read(nonce) if err != nil { - return + return nil, nil, err } self.Raw = aesgcm.Seal(nil, nonce, self.Raw, nil) - return + return salt, nonce, nil } // Wrap bundles the message into an Envelope to transmit over the network. @@ -243,13 +239,12 @@ func (self *SentMessage) Wrap(options MessageParams) (envelope *Envelope, err er } if options.Src != nil { if err = self.sign(options.Src); err != nil { - return + return nil, err } } - if len(self.Raw) > msgMaxLength { - glog.V(logger.Error).Infof("Message size must not exceed %d bytes", msgMaxLength) - err = errors.New("Oversized message") - return + if len(self.Raw) > MaxMessageLength { + glog.V(logger.Error).Infof("Message size must not exceed %d bytes", MaxMessageLength) + return nil, errors.New("Oversized message") } var salt, nonce []byte if options.Dst != nil { @@ -260,11 +255,13 @@ func (self *SentMessage) Wrap(options MessageParams) (envelope *Envelope, err er err = errors.New("Unable to encrypt the message: neither Dst nor Key") } - if err == nil { - envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, self) - envelope.Seal(options) + if err != nil { + return nil, err } - return + + envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, self) + envelope.Seal(options) + return envelope, nil } // decryptSymmetric decrypts a message with a topic key, using AES-GCM-256. diff --git a/whisper/whisper05/peer.go b/whisper/whisperv5/peer.go similarity index 89% rename from whisper/whisper05/peer.go rename to whisper/whisperv5/peer.go index c8e1c5343f..77ae887c92 100644 --- a/whisper/whisper05/peer.go +++ b/whisper/whisperv5/peer.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper05 +package whisperv5 import ( "fmt" @@ -29,7 +29,7 @@ import ( ) // peer represents a whisper protocol peer connection. -type WhisperPeer struct { +type Peer struct { host *Whisper peer *p2p.Peer ws p2p.MsgReadWriter @@ -41,8 +41,8 @@ type WhisperPeer struct { } // newPeer creates a new whisper peer object, but does not run the handshake itself. -func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *WhisperPeer { - return &WhisperPeer{ +func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer { + return &Peer{ host: host, peer: remote, ws: rw, @@ -54,24 +54,24 @@ func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *WhisperPeer // start initiates the peer updater, periodically broadcasting the whisper packets // into the network. -func (self *WhisperPeer) start() { +func (self *Peer) start() { go self.update() glog.V(logger.Debug).Infof("%v: whisper started", self.peer) } // stop terminates the peer updater, stopping message forwarding to it. -func (self *WhisperPeer) stop() { +func (self *Peer) stop() { close(self.quit) glog.V(logger.Debug).Infof("%v: whisper stopped", self.peer) } // handshake sends the protocol initiation status message to the remote peer and // verifies the remote status too. -func (self *WhisperPeer) handshake() error { +func (self *Peer) handshake() error { // Send the handshake status message asynchronously errc := make(chan error, 1) go func() { - errc <- p2p.Send(self.ws, statusCode, protocolVersion) + errc <- p2p.Send(self.ws, statusCode, ProtocolVersion) }() // Fetch the remote status packet and verify protocol match packet, err := self.ws.ReadMsg() @@ -89,8 +89,8 @@ func (self *WhisperPeer) handshake() error { if err != nil { return fmt.Errorf("bad status message: %v", err) } - if peerVersion != protocolVersion { - return fmt.Errorf("protocol version mismatch %d != %d", peerVersion, protocolVersion) + if peerVersion != ProtocolVersion { + return fmt.Errorf("protocol version mismatch %d != %d", peerVersion, ProtocolVersion) } // Wait until out own status is consumed too if err := <-errc; err != nil { @@ -101,7 +101,7 @@ func (self *WhisperPeer) handshake() error { // update executes periodic operations on the peer, including message transmission // and expiration. -func (self *WhisperPeer) update() { +func (self *Peer) update() { // Start the tickers for the updates expire := time.NewTicker(expirationCycle) transmit := time.NewTicker(transmissionCycle) @@ -125,18 +125,18 @@ func (self *WhisperPeer) update() { } // mark marks an envelope known to the peer so that it won't be sent back. -func (self *WhisperPeer) mark(envelope *Envelope) { +func (self *Peer) mark(envelope *Envelope) { self.known.Add(envelope.Hash()) } // marked checks if an envelope is already known to the remote peer. -func (self *WhisperPeer) marked(envelope *Envelope) bool { +func (self *Peer) marked(envelope *Envelope) bool { return self.known.Has(envelope.Hash()) } // expire iterates over all the known envelopes in the host and removes all // expired (unknown) ones from the known list. -func (self *WhisperPeer) expire() { +func (self *Peer) expire() { // Assemble the list of available envelopes available := set.NewNonTS() for _, envelope := range self.host.Envelopes() { @@ -158,7 +158,7 @@ func (self *WhisperPeer) expire() { // broadcast iterates over the collection of envelopes and transmits yet unknown // ones over the network. -func (self *WhisperPeer) broadcast() error { +func (self *Peer) broadcast() error { // Fetch the envelopes and collect the unknown ones envelopes := self.host.Envelopes() transmit := make([]*Envelope, 0, len(envelopes)) diff --git a/whisper/whisper05/topic.go b/whisper/whisperv5/topic.go similarity index 85% rename from whisper/whisper05/topic.go rename to whisper/whisperv5/topic.go index 721da6a5a7..1024fd1a89 100644 --- a/whisper/whisper05/topic.go +++ b/whisper/whisperv5/topic.go @@ -17,7 +17,7 @@ // Contains the Whisper protocol Topic element. For formal details please see // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#topics. -package whisper05 +package whisperv5 import ( "fmt" @@ -29,11 +29,11 @@ import ( // Topic represents a cryptographically secure, probabilistic partial // classifications of a message, determined as the first (left) 4 bytes of the // SHA3 hash of some arbitrary data given by the original author of the message. -type TopicType [topicLength]byte +type TopicType [TopicLength]byte func BytesToTopic(b []byte) (t TopicType) { - sz := topicLength - if x := len(b); x < topicLength { + sz := TopicLength + if x := len(b); x < TopicLength { sz = x } for i := 0; i < sz; i++ { @@ -43,7 +43,7 @@ func BytesToTopic(b []byte) (t TopicType) { } func HashToTopic(h common.Hash) (t TopicType) { - for i := 0; i < topicLength; i++ { + for i := 0; i < TopicLength; i++ { t[i] = h[i] } return t @@ -65,12 +65,12 @@ func (t *TopicType) UnmarshalJSON(input []byte) error { input = input[2:] } // validate the length of the input - if len(input) != topicLength*2 { - return fmt.Errorf("whisper: unmarshalJSON failed: topic must be exactly %d bytes", topicLength) + if len(input) != TopicLength*2 { + return fmt.Errorf("unmarshalJSON failed: topic must be exactly %d bytes", TopicLength) } b := common.FromHex(string(input)) if b == nil { - return fmt.Errorf("whisper: unmarshalJSON failed: wrong topic format") + return fmt.Errorf("unmarshalJSON failed: wrong topic format") } *t = BytesToTopic(b) return nil diff --git a/whisper/whisper05/whisper.go b/whisper/whisperv5/whisper.go similarity index 84% rename from whisper/whisper05/whisper.go rename to whisper/whisperv5/whisper.go index 7835e9884f..bf4583c588 100644 --- a/whisper/whisper05/whisper.go +++ b/whisper/whisperv5/whisper.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package whisper05 +package whisperv5 import ( "bytes" @@ -30,11 +30,8 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/rpc" - - "golang.org/x/crypto/pbkdf2" - "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/pbkdf2" set "gopkg.in/fatih/set.v0" ) @@ -53,52 +50,40 @@ type Whisper struct { expirations map[uint32]*set.SetNonTS // Message expiration pool poolMu sync.RWMutex // Mutex to sync the message and expiration pools - peers map[*WhisperPeer]struct{} // Set of currently active peers - peerMu sync.RWMutex // Mutex to sync the active peer set + peers map[*Peer]struct{} // Set of currently active peers + peerMu sync.RWMutex // Mutex to sync the active peer set - mailServer *MailServer + mailServer MailServer quit chan struct{} } // New creates a Whisper client ready to communicate through the Ethereum P2P network. // Param s should be passed if you want to implement mail server, otherwise nil. -func New(s *MailServer) *Whisper { +func New(server MailServer) *Whisper { whisper := &Whisper{ privateKeys: make(map[string]*ecdsa.PrivateKey), topicKeys: make(map[string][]byte), envelopes: make(map[common.Hash]*Envelope), messages: make(map[common.Hash]*ReceivedMessage), expirations: make(map[uint32]*set.SetNonTS), - peers: make(map[*WhisperPeer]struct{}), - mailServer: s, + peers: make(map[*Peer]struct{}), + mailServer: server, quit: make(chan struct{}), } whisper.filters = NewFilters(whisper) // p2p whisper sub protocol handler whisper.protocol = p2p.Protocol{ - Name: protocolName, - Version: uint(protocolVersion), - Length: 2, - Run: whisper.handlePeer, + Name: ProtocolName, + Version: uint(ProtocolVersion), + Length: NumberOfMessageCodes, + Run: whisper.HandlePeer, } return whisper } -// APIs returns the RPC descriptors the Whisper implementation offers -func (s *Whisper) APIs() []rpc.API { - return []rpc.API{ - { - Namespace: protocolName, - Version: protocolVersionStr, - Service: NewPublicWhisperAPI(s), - Public: true, - }, - } -} - // Protocols returns the whisper sub-protocols ran by this particular client. func (self *Whisper) Protocols() []p2p.Protocol { return []p2p.Protocol{self.protocol} @@ -109,58 +94,47 @@ func (self *Whisper) Version() uint { return self.protocol.Version } -// MarkPeerTrusted marks specific peer trusted, which will allow it -// to send historic (expired) messages. -func (self *Whisper) MarkPeerTrusted(peerID *rpc.HexBytes) error { +func (self *Whisper) GetFilter(id int) *Filter { + return self.filters.Get(id) +} + +func (self *Whisper) getPeer(peerID []byte) (*Peer, error) { self.peerMu.Lock() defer self.peerMu.Unlock() for p, _ := range self.peers { id := p.peer.ID() - if bytes.Equal(*peerID, id[:]) { - p.trusted = true - return nil + if bytes.Equal(peerID, id[:]) { + return p, nil } } - return fmt.Errorf("Could not find peer with ID: %x", peerID) + return nil, fmt.Errorf("Could not find peer with ID: %x", peerID) } -func (self *Whisper) RequestHistoricMessages(peerID *rpc.HexBytes, data *rpc.HexBytes) error { - var wp *WhisperPeer - self.peerMu.Lock() - for p, _ := range self.peers { - id := p.peer.ID() - if bytes.Equal(*peerID, id[:]) { - p.trusted = true - wp = p - break - } +// MarkPeerTrusted marks specific peer trusted, which will allow it +// to send historic (expired) messages. +func (self *Whisper) MarkPeerTrusted(peerID []byte) error { + p, err := self.getPeer(peerID) + if err != nil { + return err } - self.peerMu.Unlock() + p.trusted = true + return nil +} - if wp == nil { - return fmt.Errorf("RequestHistoricMessages: Could not find peer with ID: %x", peerID) +func (self *Whisper) RequestHistoricMessages(peerID []byte, data []byte) error { + wp, err := self.getPeer(peerID) + if err != nil { + return err } - + wp.trusted = true return p2p.Send(wp.ws, mailRequestCode, data) } -func (self *Whisper) SendP2PMessage(peerID *rpc.HexBytes, envelope *Envelope) error { - var wp *WhisperPeer - self.peerMu.Lock() - for p, _ := range self.peers { - id := p.peer.ID() - if bytes.Equal(*peerID, id[:]) { - p.trusted = true - wp = p - break - } +func (self *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error { + wp, err := self.getPeer(peerID) + if err != nil { + return err } - self.peerMu.Unlock() - - if wp == nil { - return fmt.Errorf("SendP2PMessage: Could not find peer with ID: %x", peerID) - } - return p2p.Send(wp.ws, p2pCode, envelope) } @@ -207,7 +181,7 @@ func (self *Whisper) GetIdentity(key *ecdsa.PublicKey) *ecdsa.PrivateKey { func (self *Whisper) GenerateTopicKey(name string) error { if self.HasTopicKey(name) { - return fmt.Errorf("GenerateTopicKey: key with name [%s] already exists", name) + return fmt.Errorf("Key with name [%s] already exists", name) } key := make([]byte, aesKeyLength) @@ -215,7 +189,7 @@ func (self *Whisper) GenerateTopicKey(name string) error { if err != nil { return err } else if !validateSymmetricKey(key) { - return fmt.Errorf("GenerateTopicKey: failed to generate valid key") + return fmt.Errorf("crypto/rand failed to generate valid key") } self.keyMu.Lock() @@ -226,10 +200,10 @@ func (self *Whisper) GenerateTopicKey(name string) error { func (self *Whisper) AddTopicKey(name string, key []byte) error { if self.HasTopicKey(name) { - return fmt.Errorf("AddTopicKey: key with name [%s] already exists", name) + return fmt.Errorf("Key with name [%s] already exists", name) } - derived, err := DeriveKeyMaterial(key, EnvelopeVersion) + derived, err := deriveKeyMaterial(key, EnvelopeVersion) if err != nil { return err } @@ -293,7 +267,7 @@ func (self *Whisper) Stop() error { // handlePeer is called by the underlying P2P layer when the whisper sub-protocol // connection is negotiated. -func (self *Whisper) handlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { +func (self *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { // Create the new peer and start tracking it whisperPeer := newPeer(self, peer, rw) @@ -318,7 +292,7 @@ func (self *Whisper) handlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { } // runMessageLoop reads and processes inbound messages directly to merge into client-global state. -func (self *Whisper) runMessageLoop(p *WhisperPeer, rw p2p.MsgReadWriter) error { +func (self *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { for { // fetch the next packet packet, err := rw.ReadMsg() @@ -345,7 +319,7 @@ func (self *Whisper) runMessageLoop(p *WhisperPeer, rw p2p.MsgReadWriter) error } p.mark(envelope) if self.mailServer != nil { - (*self.mailServer).Archive(envelope) + self.mailServer.Archive(envelope) } } case p2pCode: @@ -369,7 +343,7 @@ func (self *Whisper) runMessageLoop(p *WhisperPeer, rw p2p.MsgReadWriter) error s := rlp.NewStream(packet.Payload, uint64(packet.Size)) data, err := s.Bytes() if err == nil { - (*self.mailServer).DeliverMail(p, data) + self.mailServer.DeliverMail(p, data) } else { glog.V(logger.Error).Infof("%v: bad requestHistoricMessages received: [%v]", p.peer, err) } @@ -378,6 +352,8 @@ func (self *Whisper) runMessageLoop(p *WhisperPeer, rw p2p.MsgReadWriter) error // New message types might be implemented in the future versions of Whisper. // For forward compatibility, just ignore. } + + packet.Discard() } } @@ -405,7 +381,7 @@ func (self *Whisper) add(envelope *Envelope) error { } } - if len(envelope.Data) > msgMaxLength { + if len(envelope.Data) > MaxMessageLength { return fmt.Errorf("huge messages are not allowed") } @@ -524,7 +500,7 @@ func (self *Whisper) addDecryptedMessage(msg *ReceivedMessage) { self.messages[msg.EnvelopeHash] = msg } -func validatePublicKey(k *ecdsa.PublicKey) bool { +func ValidatePublicKey(k *ecdsa.PublicKey) bool { return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0 } @@ -532,16 +508,12 @@ func validatePrivateKey(k *ecdsa.PrivateKey) bool { if k == nil || k.D == nil || k.D.Sign() == 0 { return false } - return validatePublicKey(&k.PublicKey) + return ValidatePublicKey(&k.PublicKey) } // validateSymmetricKey returns false if the key contains all zeros func validateSymmetricKey(k []byte) bool { - if len(k) == 0 { - return false - } - empty := containsOnlyZeros(k) - return !empty + return len(k) > 0 && !containsOnlyZeros(k) } func containsOnlyZeros(data []byte) bool { @@ -559,25 +531,25 @@ func bytesToIntLittleEndian(b []byte) (res uint64) { res += uint64(b[i]) * mul mul *= 256 } - return + return res } -func bytesToIntBigEndian(b []byte) (res uint64) { +func BytesToIntBigEndian(b []byte) (res uint64) { for i := 0; i < len(b); i++ { res *= 256 res += uint64(b[i]) } - return + return res } // DeriveSymmetricKey derives symmetric key material from the key or password. // pbkdf2 is used for security, in case people use password instead of randomly generated keys. -func DeriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error) { +func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error) { if version == 0 { // todo: review: kdf should run no less than 1 sec, because it's a once in a session experience - derivedKey = pbkdf2.Key(key, nil, 65356, aesKeyLength, sha256.New) + derivedKey := pbkdf2.Key(key, nil, 65356, aesKeyLength, sha256.New) + return derivedKey, nil } else { - err = fmt.Errorf("DeriveSymmetricKey: invalid envelope version: %d", version) + return nil, unknownVersionError(version) } - return }