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