mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
162 lines
3.6 KiB
Go
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
|
|
}
|