go-ethereum/whisper5/filter.go
2016-09-06 22:58:58 +02:00

162 lines
3.6 KiB
Go

package whisper5
import (
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/common"
)
type Filter struct {
Src *ecdsa.PublicKey // Sender of the message
Dst *ecdsa.PublicKey // Recipient of the message
KeyAsym *ecdsa.PrivateKey // Private Key of recipient
Topics []TopicType // Topics to filter messages with
KeySym []byte // Key associated with the Topic
TopicKeyHash common.Hash // The Keccak256Hash of the symmetric key
PoW int // Proof of work as described in the Whisper spec
Fn func(msg *ReceivedMessage) // Handler in case of a match
}
type Filters struct {
id int
watchers map[int]*Filter
ch chan Envelope
quit chan struct{}
whisper *Whisper
}
func NewFilters(w *Whisper) *Filters {
return &Filters{
ch: make(chan Envelope),
watchers: make(map[int]*Filter),
quit: make(chan struct{}),
whisper: w,
}
}
func (self *Filters) Start() {
go self.loop()
}
func (self *Filters) Stop() {
close(self.quit)
}
func (self *Filters) Notify(env *Envelope) {
self.ch <- *env
}
func (self *Filters) Install(watcher *Filter) int {
self.watchers[self.id] = watcher
ret := self.id
self.id++
return ret
}
func (self *Filters) Uninstall(id int) {
delete(self.watchers, id)
}
func (self *Filters) Get(i int) *Filter {
return self.watchers[i]
}
func (self *Filters) loop() {
for {
select {
case <-self.quit:
return
case envelope := <-self.ch:
self.processEnvelope(&envelope)
}
}
}
func (self *Filters) processEnvelope(envelope *Envelope) {
var msg *ReceivedMessage
for _, watcher := range self.watchers {
match := false
if msg != nil {
match = watcher.MatchMessage(msg)
} else {
match = watcher.MatchEnvelope(envelope)
if match {
msg = envelope.Open(watcher)
}
}
if match && msg != nil {
watcher.Trigger(msg)
}
}
if msg != nil {
go self.whisper.addDecryptedMessage(msg)
}
}
func (self Filter) expectsAsymmetricEncryption() bool {
return self.KeyAsym != nil
}
func (self Filter) expectsSymmetricEncryption() bool {
return self.KeySym != nil
}
func (self Filter) Trigger(msg *ReceivedMessage) {
// todo: save msg hash in the filter
self.Fn(msg)
}
func (self Filter) MatchMessage(msg *ReceivedMessage) bool {
if self.PoW > 0 && msg.PoW < self.PoW {
return false
}
if self.Src != nil && msg.Src != self.Src {
return false
}
if self.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() {
return self.Dst == msg.Dst
} else if self.expectsSymmetricEncryption() && msg.isSymmetricEncryption() {
// we need to compare the keys (or rather thier hashes), because of
// possible collision (different keys can produce the same topic).
// we also need to compare the topics, because they could be arbitrary (not related to KeySym).
if self.TopicKeyHash == msg.TopicKeyHash {
for _, t := range self.Topics {
if t == msg.Topic {
return true
}
}
return false
}
}
return false
}
func (self Filter) MatchEnvelope(envelope *Envelope) bool {
if self.PoW > 0 && envelope.pow < self.PoW {
return false
}
encryptionMethodMatch := false
if self.expectsAsymmetricEncryption() && envelope.isAsymmetric() {
encryptionMethodMatch = true
if self.Topics == nil {
return true // wildcard
}
} else if self.expectsSymmetricEncryption() && envelope.isSymmetric() {
encryptionMethodMatch = true
}
if encryptionMethodMatch {
for _, t := range self.Topics {
if t == envelope.Topic {
return true
}
}
return false
}
return false
}