github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/whisper/whisperv5/filter.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package whisperv5
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	crand "crypto/rand"
    22  	"fmt"
    23  	"sync"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/log"
    27  )
    28  
    29  type Filter struct {
    30  	Src        *ecdsa.PublicKey  // Sender of the message
    31  	KeyAsym    *ecdsa.PrivateKey // Private Key of recipient
    32  	KeySym     []byte            // Key associated with the Topic
    33  	Topics     []TopicType       // Topics to filter messages with
    34  	PoW        float64           // Proof of work as described in the Whisper spec
    35  	AcceptP2P  bool              // Indicates whether this filter is interested in direct peer-to-peer messages
    36  	SymKeyHash common.Hash       // The Keccak256Hash of the symmetric key, needed for optimization
    37  
    38  	Messages map[common.Hash]*ReceivedMessage
    39  	mutex    sync.RWMutex
    40  }
    41  
    42  type Filters struct {
    43  	watchers map[string]*Filter
    44  	whisper  *Whisper
    45  	mutex    sync.RWMutex
    46  }
    47  
    48  func NewFilters(w *Whisper) *Filters {
    49  	return &Filters{
    50  		watchers: make(map[string]*Filter),
    51  		whisper:  w,
    52  	}
    53  }
    54  
    55  func (fs *Filters) generateRandomID() (id string, err error) {
    56  	buf := make([]byte, 20)
    57  	for i := 0; i < 3; i++ {
    58  		_, err = crand.Read(buf)
    59  		if err != nil {
    60  			continue
    61  		}
    62  		if !validateSymmetricKey(buf) {
    63  			err = fmt.Errorf("error in generateRandomID: crypto/rand failed to generate random data")
    64  			continue
    65  		}
    66  		id = common.Bytes2Hex(buf)
    67  		if fs.watchers[id] != nil {
    68  			err = fmt.Errorf("error in generateRandomID: generated same ID twice")
    69  			continue
    70  		}
    71  		return id, err
    72  	}
    73  
    74  	return "", err
    75  }
    76  
    77  func (fs *Filters) Install(watcher *Filter) (string, error) {
    78  	if watcher.Messages == nil {
    79  		watcher.Messages = make(map[common.Hash]*ReceivedMessage)
    80  	}
    81  
    82  	fs.mutex.Lock()
    83  	defer fs.mutex.Unlock()
    84  
    85  	id, err := fs.generateRandomID()
    86  	if err == nil {
    87  		fs.watchers[id] = watcher
    88  	}
    89  	return id, err
    90  }
    91  
    92  func (fs *Filters) Uninstall(id string) {
    93  	fs.mutex.Lock()
    94  	defer fs.mutex.Unlock()
    95  	delete(fs.watchers, id)
    96  }
    97  
    98  func (fs *Filters) Get(id string) *Filter {
    99  	fs.mutex.RLock()
   100  	defer fs.mutex.RUnlock()
   101  	return fs.watchers[id]
   102  }
   103  
   104  func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
   105  	fs.mutex.RLock()
   106  	var msg *ReceivedMessage
   107  	for j, watcher := range fs.watchers {
   108  		if p2pMessage && !watcher.AcceptP2P {
   109  			log.Trace(fmt.Sprintf("msg [%x], filter [%s]: p2p messages are not allowed", env.Hash(), j))
   110  			continue
   111  		}
   112  
   113  		var match bool
   114  		if msg != nil {
   115  			match = watcher.MatchMessage(msg)
   116  		} else {
   117  			match = watcher.MatchEnvelope(env)
   118  			if match {
   119  				msg = env.Open(watcher)
   120  				if msg == nil {
   121  					log.Trace(fmt.Sprintf("msg [%x], filter [%s]: failed to open", env.Hash(), j))
   122  				}
   123  			} else {
   124  				log.Trace(fmt.Sprintf("msg [%x], filter [%s]: does not match", env.Hash(), j))
   125  			}
   126  		}
   127  
   128  		if match && msg != nil {
   129  			watcher.Trigger(msg)
   130  		}
   131  	}
   132  	fs.mutex.RUnlock() // we need to unlock before calling addDecryptedMessage
   133  
   134  	if msg != nil {
   135  		fs.whisper.addDecryptedMessage(msg)
   136  	}
   137  }
   138  
   139  func (f *Filter) expectsAsymmetricEncryption() bool {
   140  	return f.KeyAsym != nil
   141  }
   142  
   143  func (f *Filter) expectsSymmetricEncryption() bool {
   144  	return f.KeySym != nil
   145  }
   146  
   147  func (f *Filter) Trigger(msg *ReceivedMessage) {
   148  	f.mutex.Lock()
   149  	defer f.mutex.Unlock()
   150  
   151  	if _, exist := f.Messages[msg.EnvelopeHash]; !exist {
   152  		f.Messages[msg.EnvelopeHash] = msg
   153  	}
   154  }
   155  
   156  func (f *Filter) Retrieve() (all []*ReceivedMessage) {
   157  	f.mutex.Lock()
   158  	defer f.mutex.Unlock()
   159  
   160  	all = make([]*ReceivedMessage, 0, len(f.Messages))
   161  	for _, msg := range f.Messages {
   162  		all = append(all, msg)
   163  	}
   164  	f.Messages = make(map[common.Hash]*ReceivedMessage) // delete old messages
   165  	return all
   166  }
   167  
   168  func (f *Filter) MatchMessage(msg *ReceivedMessage) bool {
   169  	if f.PoW > 0 && msg.PoW < f.PoW {
   170  		return false
   171  	}
   172  	if f.Src != nil && !IsPubKeyEqual(msg.Src, f.Src) {
   173  		return false
   174  	}
   175  
   176  	if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() {
   177  		return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic)
   178  	} else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() {
   179  		return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic)
   180  	}
   181  	return false
   182  }
   183  
   184  func (f *Filter) MatchEnvelope(envelope *Envelope) bool {
   185  	if f.PoW > 0 && envelope.pow < f.PoW {
   186  		return false
   187  	}
   188  
   189  	if f.expectsAsymmetricEncryption() && envelope.isAsymmetric() {
   190  		return f.MatchTopic(envelope.Topic)
   191  	} else if f.expectsSymmetricEncryption() && envelope.IsSymmetric() {
   192  		return f.MatchTopic(envelope.Topic)
   193  	}
   194  	return false
   195  }
   196  
   197  func (f *Filter) MatchTopic(topic TopicType) bool {
   198  	if len(f.Topics) == 0 {
   199  		// any topic matches
   200  		return true
   201  	}
   202  
   203  	for _, t := range f.Topics {
   204  		if t == topic {
   205  			return true
   206  		}
   207  	}
   208  	return false
   209  }
   210  
   211  func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool {
   212  	if !ValidatePublicKey(a) {
   213  		return false
   214  	} else if !ValidatePublicKey(b) {
   215  		return false
   216  	}
   217  	// the Curve is always the same, just compare the points
   218  	return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0
   219  }