mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
whisper: refactoring (documenting mostly)
This commit is contained in:
parent
3b57070408
commit
b6b8488390
6 changed files with 163 additions and 157 deletions
|
|
@ -526,7 +526,7 @@ func messageLoop() {
|
||||||
messages := f.Retrieve()
|
messages := f.Retrieve()
|
||||||
for _, msg := range messages {
|
for _, msg := range messages {
|
||||||
if *fileExMode || len(msg.Payload) > 2048 {
|
if *fileExMode || len(msg.Payload) > 2048 {
|
||||||
saveMessageInFile(msg)
|
writeMessageToFile(*argSaveDir, msg)
|
||||||
} else {
|
} else {
|
||||||
printMessageInfo(msg)
|
printMessageInfo(msg)
|
||||||
}
|
}
|
||||||
|
|
@ -553,7 +553,7 @@ func printMessageInfo(msg *whisper.ReceivedMessage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveMessageInFile(msg *whisper.ReceivedMessage) {
|
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
||||||
timestamp := fmt.Sprintf("%d", msg.Sent)
|
timestamp := fmt.Sprintf("%d", msg.Sent)
|
||||||
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
||||||
|
|
||||||
|
|
@ -565,8 +565,8 @@ func saveMessageInFile(msg *whisper.ReceivedMessage) {
|
||||||
if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||||
// message from myself: don't save, only report
|
// message from myself: don't save, only report
|
||||||
fmt.Printf("\n%s <%x>: message received: '%s'\n", timestamp, address, name)
|
fmt.Printf("\n%s <%x>: message received: '%s'\n", timestamp, address, name)
|
||||||
} else if len(*argSaveDir) > 0 {
|
} else if len(dir) > 0 {
|
||||||
fullpath := filepath.Join(*argSaveDir, name)
|
fullpath := filepath.Join(dir, name)
|
||||||
err := ioutil.WriteFile(fullpath, msg.Payload, 0644)
|
err := ioutil.WriteFile(fullpath, msg.Payload, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
)
|
)
|
||||||
|
|
||||||
var whisperOffLineErr = errors.New("whisper is offline")
|
var whisperOfflineErr = errors.New("whisper is offline")
|
||||||
|
|
||||||
// PublicWhisperAPI provides the whisper RPC service.
|
// PublicWhisperAPI provides the whisper RPC service.
|
||||||
type PublicWhisperAPI struct {
|
type PublicWhisperAPI struct {
|
||||||
|
|
@ -43,7 +42,7 @@ func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI {
|
||||||
// Start starts the Whisper worker threads.
|
// Start starts the Whisper worker threads.
|
||||||
func (api *PublicWhisperAPI) Start() error {
|
func (api *PublicWhisperAPI) Start() error {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return whisperOffLineErr
|
return whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.Start(nil)
|
return api.whisper.Start(nil)
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +50,7 @@ func (api *PublicWhisperAPI) Start() error {
|
||||||
// Stop stops the Whisper worker threads.
|
// Stop stops the Whisper worker threads.
|
||||||
func (api *PublicWhisperAPI) Stop() error {
|
func (api *PublicWhisperAPI) Stop() error {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return whisperOffLineErr
|
return whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.Stop()
|
return api.whisper.Stop()
|
||||||
}
|
}
|
||||||
|
|
@ -59,29 +58,31 @@ func (api *PublicWhisperAPI) Stop() error {
|
||||||
// Version returns the Whisper version this node offers.
|
// Version returns the Whisper version this node offers.
|
||||||
func (api *PublicWhisperAPI) Version() (hexutil.Uint, error) {
|
func (api *PublicWhisperAPI) Version() (hexutil.Uint, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return 0, whisperOffLineErr
|
return 0, whisperOfflineErr
|
||||||
}
|
}
|
||||||
return hexutil.Uint(api.whisper.Version()), nil
|
return hexutil.Uint(api.whisper.Version()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stats returns the Whisper statistics for diagnostics.
|
// Info returns the Whisper statistics for diagnostics.
|
||||||
func (api *PublicWhisperAPI) Info() (string, error) {
|
func (api *PublicWhisperAPI) Info() (string, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return "", whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.Stats(), nil
|
return api.whisper.Stats(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMaxMessageLength sets the maximal message length allowed by this node
|
||||||
func (api *PublicWhisperAPI) SetMaxMessageLength(val int) error {
|
func (api *PublicWhisperAPI) SetMaxMessageLength(val int) error {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return whisperOffLineErr
|
return whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.SetMaxMessageLength(val)
|
return api.whisper.SetMaxMessageLength(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMinimumPoW sets the minimal PoW required by this node
|
||||||
func (api *PublicWhisperAPI) SetMinimumPoW(val float64) error {
|
func (api *PublicWhisperAPI) SetMinimumPoW(val float64) error {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return whisperOffLineErr
|
return whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.SetMinimumPoW(val)
|
return api.whisper.SetMinimumPoW(val)
|
||||||
}
|
}
|
||||||
|
|
@ -90,71 +91,69 @@ func (api *PublicWhisperAPI) SetMinimumPoW(val float64) error {
|
||||||
// to send historic (expired) messages.
|
// to send historic (expired) messages.
|
||||||
func (api *PublicWhisperAPI) AllowP2PMessagesFromPeer(enode string) error {
|
func (api *PublicWhisperAPI) AllowP2PMessagesFromPeer(enode string) error {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return whisperOffLineErr
|
return whisperOfflineErr
|
||||||
}
|
}
|
||||||
n, err := discover.ParseNode(enode)
|
n, err := discover.ParseNode(enode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
info := "Failed to parse enode of trusted peer: " + err.Error()
|
return errors.New("failed to parse enode of trusted peer: " + err.Error())
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
return api.whisper.AllowP2PMessagesFromPeer(n.ID[:])
|
return api.whisper.AllowP2PMessagesFromPeer(n.ID[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestHistoricMessages requests the peer to deliver the old (expired) messages.
|
// HasKeyPair checks if the whisper node is configured with the private key
|
||||||
// data contains parameters (time frame, payment details, etc.), required
|
|
||||||
// by the remote email-like server. Whisper is not aware about the data format,
|
|
||||||
// it will just forward the raw data to the server.
|
|
||||||
//func (api *PublicWhisperAPI) RequestHistoricMessages(peerID hexutil.Bytes, data hexutil.Bytes) error {
|
|
||||||
// if api.whisper == nil {
|
|
||||||
// return whisperOffLineErr
|
|
||||||
// }
|
|
||||||
// return api.whisper.RequestHistoricMessages(peerID, data)
|
|
||||||
//}
|
|
||||||
|
|
||||||
// HasIdentity checks if the whisper node is configured with the private key
|
|
||||||
// of the specified public pair.
|
// of the specified public pair.
|
||||||
func (api *PublicWhisperAPI) HasKeyPair(id string) (bool, error) {
|
func (api *PublicWhisperAPI) HasKeyPair(id string) (bool, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return false, whisperOffLineErr
|
return false, whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.HasKeyPair(id), nil
|
return api.whisper.HasKeyPair(id), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIdentity deletes the specifies key if it exists.
|
// DeleteKeyPair deletes the specifies key if it exists.
|
||||||
func (api *PublicWhisperAPI) DeleteKeyPair(id string) (bool, error) {
|
func (api *PublicWhisperAPI) DeleteKeyPair(id string) (bool, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return false, whisperOffLineErr
|
return false, whisperOfflineErr
|
||||||
}
|
}
|
||||||
success := api.whisper.DeleteKeyPair(id)
|
return api.whisper.DeleteKeyPair(id), nil
|
||||||
return success, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeyPair generates a new cryptographic identity for the client, and injects
|
// NewKeyPair generates a new cryptographic identity for the client, and injects
|
||||||
// it into the known identities for message decryption.
|
// it into the known identities for message decryption.
|
||||||
func (api *PublicWhisperAPI) NewKeyPair() (string, error) {
|
func (api *PublicWhisperAPI) NewKeyPair() (string, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return "", whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.NewKeyPair()
|
return api.whisper.NewKeyPair()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublicKey returns the public key for identity id
|
// GetPublicKey returns the public key for identity id
|
||||||
func (api *PublicWhisperAPI) GetPublicKey(id string) (string, error) {
|
func (api *PublicWhisperAPI) GetPublicKey(id string) (hexutil.Bytes, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return nil, whisperOfflineErr
|
||||||
}
|
}
|
||||||
key, err := api.whisper.GetPrivateKey(id)
|
key, err := api.whisper.GetPrivateKey(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
return common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), nil
|
return crypto.FromECDSAPub(&key.PublicKey), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: delete is tests pass
|
||||||
|
//func (api *PublicWhisperAPI) GetPublicKey(id string) (string, error) {
|
||||||
|
// if api.whisper == nil {
|
||||||
|
// return "", whisperOffLineErr
|
||||||
|
// }
|
||||||
|
// key, err := api.whisper.GetPrivateKey(id)
|
||||||
|
// if err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
// return common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), nil
|
||||||
|
//}
|
||||||
|
|
||||||
// GetPrivateKey returns the private key for identity id
|
// GetPrivateKey returns the private key for identity id
|
||||||
func (api *PublicWhisperAPI) GetPrivateKey(id string) (string, error) {
|
func (api *PublicWhisperAPI) GetPrivateKey(id string) (string, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return "", whisperOfflineErr
|
||||||
}
|
}
|
||||||
key, err := api.whisper.GetPrivateKey(id)
|
key, err := api.whisper.GetPrivateKey(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -163,57 +162,71 @@ func (api *PublicWhisperAPI) GetPrivateKey(id string) (string, error) {
|
||||||
return common.ToHex(crypto.FromECDSA(key)), nil
|
return common.ToHex(crypto.FromECDSA(key)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateSymKey generates a random symmetric key and stores it under id,
|
// GenerateSymmetricKey generates a random symmetric key and stores it under id,
|
||||||
// which is then returned. Will be used in the future for session key exchange.
|
// which is then returned. Will be used in the future for session key exchange.
|
||||||
func (api *PublicWhisperAPI) GenerateSymmetricKey() (string, error) {
|
func (api *PublicWhisperAPI) GenerateSymmetricKey() (string, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return "", whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.GenerateSymKey()
|
return api.whisper.GenerateSymKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSymKeyDirect stores the key, and returns its id.
|
// AddSymmetricKeyDirect stores the key, and returns its id.
|
||||||
func (api *PublicWhisperAPI) AddSymmetricKeyDirect(key hexutil.Bytes) (string, error) {
|
func (api *PublicWhisperAPI) AddSymmetricKeyDirect(key hexutil.Bytes) (string, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return "", whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.AddSymKeyDirect(key)
|
return api.whisper.AddSymKeyDirect(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSymKeyFromPassword generates the key from password, stores it, and returns its id.
|
// AddSymmetricKeyFromPassword generates the key from password, stores it, and returns its id.
|
||||||
func (api *PublicWhisperAPI) AddSymmetricKeyFromPassword(password string) (string, error) {
|
func (api *PublicWhisperAPI) AddSymmetricKeyFromPassword(password string) (string, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return "", whisperOfflineErr
|
||||||
}
|
}
|
||||||
return api.whisper.AddSymKeyFromPassword(password)
|
return api.whisper.AddSymKeyFromPassword(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasSymKey returns true if there is a key associated with the given id.
|
// HasSymmetricKey returns true if there is a key associated with the given id.
|
||||||
// Otherwise returns false.
|
// Otherwise returns false.
|
||||||
func (api *PublicWhisperAPI) HasSymmetricKey(id string) (bool, error) {
|
func (api *PublicWhisperAPI) HasSymmetricKey(id string) (bool, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return false, whisperOffLineErr
|
return false, whisperOfflineErr
|
||||||
}
|
}
|
||||||
res := api.whisper.HasSymKey(id)
|
res := api.whisper.HasSymKey(id)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *PublicWhisperAPI) GetSymmetricKey(name string) (string, error) {
|
// GetSymmetricKey returns the symmetric key associated with the given id.
|
||||||
|
func (api *PublicWhisperAPI) GetSymmetricKey(name string) (hexutil.Bytes, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return nil, whisperOfflineErr
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := api.whisper.GetSymKey(name)
|
b, err := api.whisper.GetSymKey(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%x", b), nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteSymKey deletes the key associated with the name string if it exists.
|
// todo: delete if tests pass
|
||||||
|
//func (api *PublicWhisperAPI) GetSymmetricKey(name string) (string, error) {
|
||||||
|
// if api.whisper == nil {
|
||||||
|
// return "", whisperOffLineErr
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// b, err := api.whisper.GetSymKey(name)
|
||||||
|
// if err != nil {
|
||||||
|
// return "", err
|
||||||
|
// }
|
||||||
|
// //return fmt.Sprintf("%x", b), nil // todo: delete if tests pass
|
||||||
|
// return common.ToHex(b), nil
|
||||||
|
//}
|
||||||
|
|
||||||
|
// DeleteSymmetricKey deletes the key associated with the name string if it exists.
|
||||||
func (api *PublicWhisperAPI) DeleteSymmetricKey(name string) (bool, error) {
|
func (api *PublicWhisperAPI) DeleteSymmetricKey(name string) (bool, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return false, whisperOffLineErr
|
return false, whisperOfflineErr
|
||||||
}
|
}
|
||||||
res := api.whisper.DeleteSymKey(name)
|
res := api.whisper.DeleteSymKey(name)
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
@ -223,7 +236,7 @@ func (api *PublicWhisperAPI) DeleteSymmetricKey(name string) (bool, error) {
|
||||||
// Returns the ID of the newly created filter.
|
// Returns the ID of the newly created filter.
|
||||||
func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return "", whisperOffLineErr
|
return "", whisperOfflineErr
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := Filter{
|
filter := Filter{
|
||||||
|
|
@ -233,61 +246,44 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
||||||
AllowP2P: args.AllowP2P,
|
AllowP2P: args.AllowP2P,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
for i, bt := range args.Topics {
|
for i, bt := range args.Topics {
|
||||||
if len(bt) == 0 || len(bt) > 4 {
|
if len(bt) == 0 || len(bt) > 4 {
|
||||||
info := fmt.Sprintf("Subscribe: topic %d has wrong size: %d", i, len(bt))
|
return "", errors.New(fmt.Sprintf("subscribe: topic %d has wrong size: %d", i, len(bt)))
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
filter.Topics = append(filter.Topics, bt)
|
filter.Topics = append(filter.Topics, bt)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := ValidateKeyID(args.Key)
|
if err = ValidateKeyID(args.Key); err != nil {
|
||||||
if err != nil {
|
return "", errors.New("subscribe: " + err.Error())
|
||||||
info := "Subscribe: " + err.Error()
|
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args.SignedWith) > 0 {
|
if len(args.SignedWith) > 0 {
|
||||||
if !ValidatePublicKey(filter.Src) {
|
if !ValidatePublicKey(filter.Src) {
|
||||||
info := "Subscribe: Invalid 'SignedWith' field"
|
return "", errors.New("subscribe: invalid 'SignedWith' field")
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.Symmetric {
|
if args.Symmetric {
|
||||||
if len(args.Topics) == 0 {
|
if len(args.Topics) == 0 {
|
||||||
info := "Subscribe: at least one topic must be specified with symmetric encryption"
|
return "", errors.New("subscribe: at least one topic must be specified with symmetric encryption")
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
symKey, err := api.whisper.GetSymKey(args.Key)
|
symKey, err := api.whisper.GetSymKey(args.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
info := "Subscribe: invalid key ID"
|
return "", errors.New("subscribe: invalid key ID")
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
if !validateSymmetricKey(symKey) {
|
if !validateSymmetricKey(symKey) {
|
||||||
info := "Subscribe: retrieved key is invalid"
|
return "", errors.New("subscribe: retrieved key is invalid")
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filter.KeySym = symKey
|
filter.KeySym = symKey
|
||||||
filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym)
|
filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym)
|
||||||
} else {
|
} else {
|
||||||
filter.KeyAsym, err = api.whisper.GetPrivateKey(args.Key)
|
filter.KeyAsym, err = api.whisper.GetPrivateKey(args.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
info := "Subscribe: invalid key ID"
|
return "", errors.New("subscribe: invalid key ID")
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
if filter.KeyAsym == nil {
|
if filter.KeyAsym == nil {
|
||||||
info := "Subscribe: non-existent identity provided"
|
return "", errors.New("subscribe: non-existent identity provided")
|
||||||
log.Error(info)
|
|
||||||
return "", errors.New(info)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,7 +295,7 @@ func (api *PublicWhisperAPI) Unsubscribe(id string) {
|
||||||
api.whisper.Unsubscribe(id)
|
api.whisper.Unsubscribe(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval.
|
// GetSubscriptionMessages retrieves all the new messages matched by a filter since the last retrieval.
|
||||||
func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*WhisperMessage {
|
func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*WhisperMessage {
|
||||||
f := api.whisper.GetFilter(filterId)
|
f := api.whisper.GetFilter(filterId)
|
||||||
if f != nil {
|
if f != nil {
|
||||||
|
|
@ -309,7 +305,8 @@ func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*Whisper
|
||||||
return toWhisperMessages(nil)
|
return toWhisperMessages(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMessages retrieves all the known messages that match a specific filter.
|
// GetMessages retrieves all the floating messages that match a specific filter.
|
||||||
|
// It is likely to be called once per session, right after Subscribe call.
|
||||||
func (api *PublicWhisperAPI) GetMessages(filterId string) []*WhisperMessage {
|
func (api *PublicWhisperAPI) GetMessages(filterId string) []*WhisperMessage {
|
||||||
all := api.whisper.Messages(filterId)
|
all := api.whisper.Messages(filterId)
|
||||||
return toWhisperMessages(all)
|
return toWhisperMessages(all)
|
||||||
|
|
@ -327,7 +324,7 @@ func toWhisperMessages(messages []*ReceivedMessage) []*WhisperMessage {
|
||||||
// Post creates a whisper message and injects it into the network for distribution.
|
// Post creates a whisper message and injects it into the network for distribution.
|
||||||
func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
||||||
if api.whisper == nil {
|
if api.whisper == nil {
|
||||||
return whisperOffLineErr
|
return whisperOfflineErr
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
@ -340,96 +337,69 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args.Key) == 0 {
|
if len(args.Key) == 0 {
|
||||||
info := "Post: key is missing"
|
return errors.New("post: key is missing")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args.SignWith) > 0 {
|
if len(args.SignWith) > 0 {
|
||||||
params.Src, err = api.whisper.GetPrivateKey(args.SignWith)
|
params.Src, err = api.whisper.GetPrivateKey(args.SignWith)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err.Error())
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if params.Src == nil {
|
if params.Src == nil {
|
||||||
info := "Post: empty identity"
|
return errors.New("post: empty identity")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args.Topic) == TopicLength {
|
if len(args.Topic) == TopicLength {
|
||||||
params.Topic = BytesToTopic(args.Topic)
|
params.Topic = BytesToTopic(args.Topic)
|
||||||
} else if len(args.Topic) != 0 {
|
} else if len(args.Topic) != 0 {
|
||||||
info := fmt.Sprintf("Post: wrong topic size %d", len(args.Topic))
|
return errors.New(fmt.Sprintf("post: wrong topic size %d", len(args.Topic)))
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.Type == "sym" {
|
if args.Type == "sym" {
|
||||||
err = ValidateKeyID(args.Key)
|
if err = ValidateKeyID(args.Key); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Error(err.Error())
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
params.KeySym, err = api.whisper.GetSymKey(args.Key)
|
params.KeySym, err = api.whisper.GetSymKey(args.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err.Error())
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !validateSymmetricKey(params.KeySym) {
|
if !validateSymmetricKey(params.KeySym) {
|
||||||
info := "Post: key for symmetric encryption is invalid"
|
return errors.New("post: key for symmetric encryption is invalid")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
if len(params.Topic) == 0 {
|
if len(params.Topic) == 0 {
|
||||||
info := "Post: topic is missing for symmetric encryption"
|
return errors.New("post: topic is missing for symmetric encryption")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
} else if args.Type == "asym" {
|
} else if args.Type == "asym" {
|
||||||
params.Dst = crypto.ToECDSAPub(common.FromHex(args.Key))
|
params.Dst = crypto.ToECDSAPub(common.FromHex(args.Key))
|
||||||
if !ValidatePublicKey(params.Dst) {
|
if !ValidatePublicKey(params.Dst) {
|
||||||
info := "Post: public key for asymmetric encryption is invalid"
|
return errors.New("post: public key for asymmetric encryption is invalid")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info := "Post: wrong type (sym/asym)"
|
return errors.New("post: wrong type (sym/asym)")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// encrypt and send
|
// encrypt and send
|
||||||
message := NewSentMessage(¶ms)
|
message := NewSentMessage(¶ms)
|
||||||
if message == nil {
|
if message == nil {
|
||||||
info := "Post: failed create new message, probably due to failed rand function (OS level)"
|
return errors.New("post: failed create new message, probably due to failed rand function (OS level)")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
envelope, err := message.Wrap(¶ms)
|
envelope, err := message.Wrap(¶ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err.Error())
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if envelope.size() > api.whisper.maxMsgLength {
|
if envelope.size() > api.whisper.maxMsgLength {
|
||||||
info := "Post: message is too big"
|
return errors.New("post: message is too big")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args.TargetPeer) != 0 {
|
if len(args.TargetPeer) != 0 {
|
||||||
n, err := discover.ParseNode(args.TargetPeer)
|
n, err := discover.ParseNode(args.TargetPeer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
info := "Post: failed to parse enode of target peer: " + err.Error()
|
return errors.New("post: failed to parse enode of target peer: " + err.Error())
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
return api.whisper.SendP2PMessage(n.ID[:], envelope)
|
return api.whisper.SendP2PMessage(n.ID[:], envelope)
|
||||||
} else if args.PowTarget < api.whisper.minPoW {
|
} else if args.PowTarget < api.whisper.minPoW {
|
||||||
info := "Post: target PoW is less than minimum PoW, the message can not be sent"
|
return errors.New("post: target PoW is less than minimum PoW, the message can not be sent")
|
||||||
log.Error(info)
|
|
||||||
return errors.New(info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.whisper.Send(envelope)
|
return api.whisper.Send(envelope)
|
||||||
|
|
@ -473,12 +443,13 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.Type == "sym" {
|
switch obj.Type {
|
||||||
|
case "sym":
|
||||||
args.Symmetric = true
|
args.Symmetric = true
|
||||||
} else if obj.Type == "asym" {
|
case "asym":
|
||||||
args.Symmetric = false
|
args.Symmetric = false
|
||||||
} else {
|
default:
|
||||||
return fmt.Errorf("Wrong type (sym/asym")
|
return errors.New("wrong type (sym/asym")
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Key = obj.Key
|
args.Key = obj.Key
|
||||||
|
|
|
||||||
|
|
@ -94,11 +94,11 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
|
||||||
fs.mutex.RLock()
|
fs.mutex.RLock()
|
||||||
defer fs.mutex.RUnlock()
|
defer fs.mutex.RUnlock()
|
||||||
|
|
||||||
j := -1
|
i := -1 // only used for logging info
|
||||||
for _, watcher := range fs.watchers {
|
for _, watcher := range fs.watchers {
|
||||||
j++
|
i++
|
||||||
if p2pMessage && !watcher.AllowP2P {
|
if p2pMessage && !watcher.AllowP2P {
|
||||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: p2p messages are not allowed", env.Hash(), j))
|
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: p2p messages are not allowed", env.Hash(), i))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,10 +110,10 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
|
||||||
if match {
|
if match {
|
||||||
msg = env.Open(watcher)
|
msg = env.Open(watcher)
|
||||||
if msg == nil {
|
if msg == nil {
|
||||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: failed to open", env.Hash(), j))
|
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: failed to open", env.Hash(), i))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: does not match", env.Hash(), j))
|
log.Trace(fmt.Sprintf("msg [%x], filter [%d]: does not match", env.Hash(), i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,16 +203,16 @@ func (f *Filter) MatchTopic(topic TopicType) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, bt := range f.Topics {
|
for _, bt := range f.Topics {
|
||||||
if MatchSingleTopic(topic, bt) {
|
if matchSingleTopic(topic, bt) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func MatchSingleTopic(topic TopicType, bt []byte) bool {
|
func matchSingleTopic(topic TopicType, bt []byte) bool {
|
||||||
if len(bt) > 4 {
|
if len(bt) > 4 {
|
||||||
bt = bt[0:4]
|
bt = bt[:4]
|
||||||
}
|
}
|
||||||
|
|
||||||
for j, b := range bt {
|
for j, b := range bt {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
mrand "math/rand"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -132,7 +131,7 @@ func (msg *SentMessage) appendPadding(params *MessageParams) error {
|
||||||
panic("please fix the padding algorithm before releasing new version")
|
panic("please fix the padding algorithm before releasing new version")
|
||||||
}
|
}
|
||||||
buf := make([]byte, padSize)
|
buf := make([]byte, padSize)
|
||||||
_, err := mrand.Read(buf[1:])
|
_, err := crand.Read(buf[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,10 @@ func initialize(t *testing.T) {
|
||||||
topics := make([]TopicType, 0)
|
topics := make([]TopicType, 0)
|
||||||
topics = append(topics, sharedTopic)
|
topics = append(topics, sharedTopic)
|
||||||
f := Filter{KeySym: sharedKey}
|
f := Filter{KeySym: sharedKey}
|
||||||
f.Topics = make([][]byte, 1)
|
f.Topics = [][]byte{topics[0][:]}
|
||||||
f.Topics[0] = topics[0][:]
|
// todo: delete if pass
|
||||||
|
//f.Topics = make([][]byte, 1)
|
||||||
|
//f.Topics[0] = topics[0][:]
|
||||||
node.filerId, err = node.shh.Watch(&f)
|
node.filerId, err = node.shh.Watch(&f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to install the filter: %s.", err)
|
t.Fatalf("failed to install the filter: %s.", err)
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,12 @@ type Statistics struct {
|
||||||
// Whisper represents a dark communication interface through the Ethereum
|
// Whisper represents a dark communication interface through the Ethereum
|
||||||
// network, using its very own P2P communication layer.
|
// network, using its very own P2P communication layer.
|
||||||
type Whisper struct {
|
type Whisper struct {
|
||||||
protocol p2p.Protocol
|
protocol p2p.Protocol // Protocol description and parameters
|
||||||
filters *Filters
|
filters *Filters // Message filters installed with Subscribe function
|
||||||
|
|
||||||
privateKeys map[string]*ecdsa.PrivateKey
|
privateKeys map[string]*ecdsa.PrivateKey // Private key storage
|
||||||
symKeys map[string][]byte
|
symKeys map[string][]byte // Symmetric key storage
|
||||||
keyMu sync.RWMutex
|
keyMu sync.RWMutex // Mutex associated with key storages
|
||||||
|
|
||||||
envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node
|
envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node
|
||||||
expirations map[uint32]*set.SetNonTS // Message expiration pool
|
expirations map[uint32]*set.SetNonTS // Message expiration pool
|
||||||
|
|
@ -60,17 +60,17 @@ type Whisper struct {
|
||||||
peers map[*Peer]struct{} // Set of currently active peers
|
peers map[*Peer]struct{} // Set of currently active peers
|
||||||
peerMu sync.RWMutex // Mutex to sync the active peer set
|
peerMu sync.RWMutex // Mutex to sync the active peer set
|
||||||
|
|
||||||
mailServer MailServer
|
messageQueue chan *Envelope // Message queue for normal whisper messages
|
||||||
|
p2pMsgQueue chan *Envelope // Message queue for peer-to-peer messages (not to be forwarded any further)
|
||||||
|
quit chan struct{} // Channel used for graceful exit
|
||||||
|
|
||||||
messageQueue chan *Envelope
|
minPoW float64 // Minimal PoW required by the whisper node
|
||||||
p2pMsgQueue chan *Envelope
|
maxMsgLength int // Maximal message length allowed by the whisper node
|
||||||
quit chan struct{}
|
overflow bool // Indicator of message queue overflow
|
||||||
|
|
||||||
stats Statistics
|
stats Statistics // Statistics of whisper node
|
||||||
|
|
||||||
minPoW float64
|
mailServer MailServer // MailServer interface
|
||||||
maxMsgLength int
|
|
||||||
overflow bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
|
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
|
||||||
|
|
@ -113,6 +113,8 @@ func (w *Whisper) APIs() []rpc.API {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterServer registers MailServer interface.
|
||||||
|
// MailServer will process all the incoming messages with p2pRequestCode.
|
||||||
func (w *Whisper) RegisterServer(server MailServer) {
|
func (w *Whisper) RegisterServer(server MailServer) {
|
||||||
w.mailServer = server
|
w.mailServer = server
|
||||||
}
|
}
|
||||||
|
|
@ -127,6 +129,7 @@ func (w *Whisper) Version() uint {
|
||||||
return w.protocol.Version
|
return w.protocol.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMaxMessageLength sets the maximal message length allowed by this node
|
||||||
func (w *Whisper) SetMaxMessageLength(val int) error {
|
func (w *Whisper) SetMaxMessageLength(val int) error {
|
||||||
if val <= 0 {
|
if val <= 0 {
|
||||||
return fmt.Errorf("Invalid message length: %d", val)
|
return fmt.Errorf("Invalid message length: %d", val)
|
||||||
|
|
@ -135,6 +138,7 @@ func (w *Whisper) SetMaxMessageLength(val int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMinimumPoW sets the minimal PoW required by this node
|
||||||
func (w *Whisper) SetMinimumPoW(val float64) error {
|
func (w *Whisper) SetMinimumPoW(val float64) error {
|
||||||
if val <= 0.0 {
|
if val <= 0.0 {
|
||||||
return fmt.Errorf("Invalid PoW: %f", val)
|
return fmt.Errorf("Invalid PoW: %f", val)
|
||||||
|
|
@ -166,6 +170,11 @@ func (w *Whisper) AllowP2PMessagesFromPeer(peerID []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer,
|
||||||
|
// which is known to implement MailServer interface, and is supposed to process this
|
||||||
|
// request and respond with a number of peer-to-peer messages (possibly expired),
|
||||||
|
// which are not supposed to be forwarded any further.
|
||||||
|
// The whisper protocol is agnostic of the format and contents of envelope.
|
||||||
func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) error {
|
func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) error {
|
||||||
p, err := w.getPeer(peerID)
|
p, err := w.getPeer(peerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -175,14 +184,17 @@ func (w *Whisper) RequestHistoricMessages(peerID []byte, envelope *Envelope) err
|
||||||
return p2p.Send(p.ws, p2pRequestCode, envelope)
|
return p2p.Send(p.ws, p2pRequestCode, envelope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendP2PMessage sends a peer-to-peer message to a specific peer.
|
||||||
func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error {
|
func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error {
|
||||||
p, err := w.getPeer(peerID)
|
p, err := w.getPeer(peerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return p2p.Send(p.ws, p2pCode, envelope)
|
//return p2p.Send(p.ws, p2pCode, envelope) // todo: delete if tests pass
|
||||||
|
return w.SendP2PDirect(p, envelope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendP2PDirect sends a peer-to-peer message to a specific peer.
|
||||||
func (w *Whisper) SendP2PDirect(peer *Peer, envelope *Envelope) error {
|
func (w *Whisper) SendP2PDirect(peer *Peer, envelope *Envelope) error {
|
||||||
return p2p.Send(peer.ws, p2pCode, envelope)
|
return p2p.Send(peer.ws, p2pCode, envelope)
|
||||||
}
|
}
|
||||||
|
|
@ -247,6 +259,8 @@ func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateSymKey generates a random symmetric key and stores it under id,
|
||||||
|
// which is then returned. Will be used in the future for session key exchange.
|
||||||
func (w *Whisper) GenerateSymKey() (string, error) {
|
func (w *Whisper) GenerateSymKey() (string, error) {
|
||||||
const size = aesKeyLength * 2
|
const size = aesKeyLength * 2
|
||||||
buf := make([]byte, size)
|
buf := make([]byte, size)
|
||||||
|
|
@ -281,6 +295,7 @@ func (w *Whisper) GenerateSymKey() (string, error) {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddSymKeyDirect stores the key, and returns its id.
|
||||||
func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
||||||
if len(key) != aesKeyLength {
|
if len(key) != aesKeyLength {
|
||||||
return "", fmt.Errorf("Wrong key size: %d", len(key))
|
return "", fmt.Errorf("Wrong key size: %d", len(key))
|
||||||
|
|
@ -301,6 +316,7 @@ func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddSymKeyFromPassword generates the key from password, stores it, and returns its id.
|
||||||
func (w *Whisper) AddSymKeyFromPassword(password string) (string, error) {
|
func (w *Whisper) AddSymKeyFromPassword(password string) (string, error) {
|
||||||
id, err := GenerateRandomID()
|
id, err := GenerateRandomID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -326,12 +342,15 @@ func (w *Whisper) AddSymKeyFromPassword(password string) (string, error) {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasSymKey returns true if there is a key associated with the given id.
|
||||||
|
// Otherwise returns false.
|
||||||
func (w *Whisper) HasSymKey(id string) bool {
|
func (w *Whisper) HasSymKey(id string) bool {
|
||||||
w.keyMu.RLock()
|
w.keyMu.RLock()
|
||||||
defer w.keyMu.RUnlock()
|
defer w.keyMu.RUnlock()
|
||||||
return w.symKeys[id] != nil
|
return w.symKeys[id] != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteSymKey deletes the key associated with the name string if it exists.
|
||||||
func (w *Whisper) DeleteSymKey(id string) bool {
|
func (w *Whisper) DeleteSymKey(id string) bool {
|
||||||
w.keyMu.Lock()
|
w.keyMu.Lock()
|
||||||
defer w.keyMu.Unlock()
|
defer w.keyMu.Unlock()
|
||||||
|
|
@ -342,6 +361,7 @@ func (w *Whisper) DeleteSymKey(id string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSymKey returns the symmetric key associated with the given id.
|
||||||
func (w *Whisper) GetSymKey(id string) ([]byte, error) {
|
func (w *Whisper) GetSymKey(id string) ([]byte, error) {
|
||||||
w.keyMu.RLock()
|
w.keyMu.RLock()
|
||||||
defer w.keyMu.RUnlock()
|
defer w.keyMu.RUnlock()
|
||||||
|
|
@ -351,12 +371,13 @@ func (w *Whisper) GetSymKey(id string) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("non-existent key ID")
|
return nil, fmt.Errorf("non-existent key ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch installs a new message handler to run in case a matching packet arrives
|
// Watch installs a new message handler used for filtering, decrypting
|
||||||
// from the whisper network.
|
// and subsequent storing of incoming messages.
|
||||||
func (w *Whisper) Watch(f *Filter) (string, error) {
|
func (w *Whisper) Watch(f *Filter) (string, error) {
|
||||||
return w.filters.Install(f)
|
return w.filters.Install(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFilter returns the filter by id.
|
||||||
func (w *Whisper) GetFilter(id string) *Filter {
|
func (w *Whisper) GetFilter(id string) *Filter {
|
||||||
return w.filters.Get(id)
|
return w.filters.Get(id)
|
||||||
}
|
}
|
||||||
|
|
@ -662,6 +683,7 @@ func (w *Whisper) expire() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stats returns the whisper node statistics.
|
||||||
func (w *Whisper) Stats() string {
|
func (w *Whisper) Stats() string {
|
||||||
result := fmt.Sprintf("Memory usage: %d bytes. Average messages cleared per expiry cycle: %d. Total messages cleared: %d.",
|
result := fmt.Sprintf("Memory usage: %d bytes. Average messages cleared per expiry cycle: %d. Total messages cleared: %d.",
|
||||||
w.stats.memoryUsed, w.stats.totalMessagesCleared/w.stats.cycles, w.stats.totalMessagesCleared)
|
w.stats.memoryUsed, w.stats.totalMessagesCleared/w.stats.cycles, w.stats.totalMessagesCleared)
|
||||||
|
|
@ -669,6 +691,9 @@ func (w *Whisper) Stats() string {
|
||||||
result += fmt.Sprintf(" Latest expiry cycle cleared %d messages (%d bytes).",
|
result += fmt.Sprintf(" Latest expiry cycle cleared %d messages (%d bytes).",
|
||||||
w.stats.messagesCleared, w.stats.memoryCleared)
|
w.stats.messagesCleared, w.stats.memoryCleared)
|
||||||
}
|
}
|
||||||
|
if w.overflow {
|
||||||
|
result += " Message queue state: overflow."
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -702,6 +727,7 @@ func (w *Whisper) Messages(id string) []*ReceivedMessage {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isEnvelopeCached checks if envelope with specific hash has already been received and cached.
|
||||||
func (w *Whisper) isEnvelopeCached(hash common.Hash) bool {
|
func (w *Whisper) isEnvelopeCached(hash common.Hash) bool {
|
||||||
w.poolMu.Lock()
|
w.poolMu.Lock()
|
||||||
defer w.poolMu.Unlock()
|
defer w.poolMu.Unlock()
|
||||||
|
|
@ -710,6 +736,7 @@ func (w *Whisper) isEnvelopeCached(hash common.Hash) bool {
|
||||||
return exist
|
return exist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset resets the node's statistics after each expiry cycle.
|
||||||
func (s *Statistics) reset() {
|
func (s *Statistics) reset() {
|
||||||
s.cycles++
|
s.cycles++
|
||||||
s.totalMessagesCleared += s.messagesCleared
|
s.totalMessagesCleared += s.messagesCleared
|
||||||
|
|
@ -718,6 +745,7 @@ func (s *Statistics) reset() {
|
||||||
s.messagesCleared = 0
|
s.messagesCleared = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateKeyID checks the format of key id.
|
||||||
func ValidateKeyID(id string) error {
|
func ValidateKeyID(id string) error {
|
||||||
const target = keyIdSize * 2
|
const target = keyIdSize * 2
|
||||||
if len(id) != target {
|
if len(id) != target {
|
||||||
|
|
@ -726,10 +754,12 @@ func ValidateKeyID(id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatePublicKey checks the format of the given public key.
|
||||||
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
|
return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validatePrivateKey checks the format of the given private key.
|
||||||
func validatePrivateKey(k *ecdsa.PrivateKey) bool {
|
func validatePrivateKey(k *ecdsa.PrivateKey) bool {
|
||||||
if k == nil || k.D == nil || k.D.Sign() == 0 {
|
if k == nil || k.D == nil || k.D.Sign() == 0 {
|
||||||
return false
|
return false
|
||||||
|
|
@ -742,6 +772,7 @@ func validateSymmetricKey(k []byte) bool {
|
||||||
return len(k) > 0 && !containsOnlyZeros(k)
|
return len(k) > 0 && !containsOnlyZeros(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// containsOnlyZeros checks if the data contain only zeros.
|
||||||
func containsOnlyZeros(data []byte) bool {
|
func containsOnlyZeros(data []byte) bool {
|
||||||
for _, b := range data {
|
for _, b := range data {
|
||||||
if b != 0 {
|
if b != 0 {
|
||||||
|
|
@ -751,6 +782,7 @@ func containsOnlyZeros(data []byte) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bytesToIntLittleEndian converts the slice to 64-bit unsigned integer.
|
||||||
func bytesToIntLittleEndian(b []byte) (res uint64) {
|
func bytesToIntLittleEndian(b []byte) (res uint64) {
|
||||||
mul := uint64(1)
|
mul := uint64(1)
|
||||||
for i := 0; i < len(b); i++ {
|
for i := 0; i < len(b); i++ {
|
||||||
|
|
@ -760,6 +792,7 @@ func bytesToIntLittleEndian(b []byte) (res uint64) {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BytesToIntBigEndian converts the slice to 64-bit unsigned integer.
|
||||||
func BytesToIntBigEndian(b []byte) (res uint64) {
|
func BytesToIntBigEndian(b []byte) (res uint64) {
|
||||||
for i := 0; i < len(b); i++ {
|
for i := 0; i < len(b); i++ {
|
||||||
res *= 256
|
res *= 256
|
||||||
|
|
@ -781,6 +814,7 @@ func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateRandomID generates a random string, which is then returned to be used as a key id
|
||||||
func GenerateRandomID() (id string, err error) {
|
func GenerateRandomID() (id string, err error) {
|
||||||
buf := make([]byte, keyIdSize)
|
buf := make([]byte, keyIdSize)
|
||||||
_, err = crand.Read(buf)
|
_, err = crand.Read(buf)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue