github.com/aquanetwork/aquachain@v1.7.8/opt/whisper/whisperv6/filter.go (about) 1 // Copyright 2016 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain 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 aquachain 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 aquachain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package whisperv6 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "sync" 23 24 "gitlab.com/aquachain/aquachain/common" 25 "gitlab.com/aquachain/aquachain/common/log" 26 "gitlab.com/aquachain/aquachain/crypto" 27 ) 28 29 // Filter represents a Whisper message filter 30 type Filter struct { 31 Src *ecdsa.PublicKey // Sender of the message 32 KeyAsym *ecdsa.PrivateKey // Private Key of recipient 33 KeySym []byte // Key associated with the Topic 34 Topics [][]byte // Topics to filter messages with 35 PoW float64 // Proof of work as described in the Whisper spec 36 AllowP2P bool // Indicates whether this filter is interested in direct peer-to-peer messages 37 SymKeyHash common.Hash // The Keccak256Hash of the symmetric key, needed for optimization 38 39 Messages map[common.Hash]*ReceivedMessage 40 mutex sync.RWMutex 41 } 42 43 // Filters represents a collection of filters 44 type Filters struct { 45 watchers map[string]*Filter 46 whisper *Whisper 47 mutex sync.RWMutex 48 } 49 50 // NewFilters returns a newly created filter collection 51 func NewFilters(w *Whisper) *Filters { 52 return &Filters{ 53 watchers: make(map[string]*Filter), 54 whisper: w, 55 } 56 } 57 58 // Install will add a new filter to the filter collection 59 func (fs *Filters) Install(watcher *Filter) (string, error) { 60 if watcher.KeySym != nil && watcher.KeyAsym != nil { 61 return "", fmt.Errorf("filters must choose between symmetric and asymmetric keys") 62 } 63 64 if watcher.Messages == nil { 65 watcher.Messages = make(map[common.Hash]*ReceivedMessage) 66 } 67 68 id, err := GenerateRandomID() 69 if err != nil { 70 return "", err 71 } 72 73 fs.mutex.Lock() 74 defer fs.mutex.Unlock() 75 76 if fs.watchers[id] != nil { 77 return "", fmt.Errorf("failed to generate unique ID") 78 } 79 80 if watcher.expectsSymmetricEncryption() { 81 watcher.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 82 } 83 84 fs.watchers[id] = watcher 85 return id, err 86 } 87 88 // Uninstall will remove a filter whose id has been specified from 89 // the filter collection 90 func (fs *Filters) Uninstall(id string) bool { 91 fs.mutex.Lock() 92 defer fs.mutex.Unlock() 93 if fs.watchers[id] != nil { 94 delete(fs.watchers, id) 95 return true 96 } 97 return false 98 } 99 100 // Get returns a filter from the collection with a specific ID 101 func (fs *Filters) Get(id string) *Filter { 102 fs.mutex.RLock() 103 defer fs.mutex.RUnlock() 104 return fs.watchers[id] 105 } 106 107 // NotifyWatchers notifies any filter that has declared interest 108 // for the envelope's topic. 109 func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { 110 var msg *ReceivedMessage 111 112 fs.mutex.RLock() 113 defer fs.mutex.RUnlock() 114 115 i := -1 // only used for logging info 116 for _, watcher := range fs.watchers { 117 i++ 118 if p2pMessage && !watcher.AllowP2P { 119 log.Trace(fmt.Sprintf("msg [%x], filter [%d]: p2p messages are not allowed", env.Hash(), i)) 120 continue 121 } 122 123 var match bool 124 if msg != nil { 125 match = watcher.MatchMessage(msg) 126 } else { 127 match = watcher.MatchEnvelope(env) 128 if match { 129 msg = env.Open(watcher) 130 if msg == nil { 131 log.Trace("processing message: failed to open", "message", env.Hash().Hex(), "filter", i) 132 } 133 } else { 134 log.Trace("processing message: does not match", "message", env.Hash().Hex(), "filter", i) 135 } 136 } 137 138 if match && msg != nil { 139 log.Trace("processing message: decrypted", "hash", env.Hash().Hex()) 140 if watcher.Src == nil || IsPubKeyEqual(msg.Src, watcher.Src) { 141 watcher.Trigger(msg) 142 } 143 } 144 } 145 } 146 147 func (f *Filter) processEnvelope(env *Envelope) *ReceivedMessage { 148 if f.MatchEnvelope(env) { 149 msg := env.Open(f) 150 if msg != nil { 151 return msg 152 } 153 154 log.Trace("processing envelope: failed to open", "hash", env.Hash().Hex()) 155 } else { 156 log.Trace("processing envelope: does not match", "hash", env.Hash().Hex()) 157 } 158 return nil 159 } 160 161 func (f *Filter) expectsAsymmetricEncryption() bool { 162 return f.KeyAsym != nil 163 } 164 165 func (f *Filter) expectsSymmetricEncryption() bool { 166 return f.KeySym != nil 167 } 168 169 // Trigger adds a yet-unknown message to the filter's list of 170 // received messages. 171 func (f *Filter) Trigger(msg *ReceivedMessage) { 172 f.mutex.Lock() 173 defer f.mutex.Unlock() 174 175 if _, exist := f.Messages[msg.EnvelopeHash]; !exist { 176 f.Messages[msg.EnvelopeHash] = msg 177 } 178 } 179 180 // Retrieve will return the list of all received messages associated 181 // to a filter. 182 func (f *Filter) Retrieve() (all []*ReceivedMessage) { 183 f.mutex.Lock() 184 defer f.mutex.Unlock() 185 186 all = make([]*ReceivedMessage, 0, len(f.Messages)) 187 for _, msg := range f.Messages { 188 all = append(all, msg) 189 } 190 191 f.Messages = make(map[common.Hash]*ReceivedMessage) // delete old messages 192 return all 193 } 194 195 // MatchMessage checks if the filter matches an already decrypted 196 // message (i.e. a Message that has already been handled by 197 // MatchEnvelope when checked by a previous filter) 198 func (f *Filter) MatchMessage(msg *ReceivedMessage) bool { 199 if f.PoW > 0 && msg.PoW < f.PoW { 200 return false 201 } 202 203 if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() { 204 return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic) 205 } else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() { 206 return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic) 207 } 208 return false 209 } 210 211 // MatchEnvelope checks if it's worth decrypting the message. If 212 // it returns `true`, client code is expected to attempt decrypting 213 // the message and subsequently call MatchMessage. 214 func (f *Filter) MatchEnvelope(envelope *Envelope) bool { 215 if f.PoW > 0 && envelope.pow < f.PoW { 216 return false 217 } 218 219 return f.MatchTopic(envelope.Topic) 220 } 221 222 // MatchTopic checks that the filter captures a given topic. 223 func (f *Filter) MatchTopic(topic TopicType) bool { 224 if len(f.Topics) == 0 { 225 // any topic matches 226 return true 227 } 228 229 for _, bt := range f.Topics { 230 if matchSingleTopic(topic, bt) { 231 return true 232 } 233 } 234 return false 235 } 236 237 func matchSingleTopic(topic TopicType, bt []byte) bool { 238 if len(bt) > TopicLength { 239 bt = bt[:TopicLength] 240 } 241 242 if len(bt) < TopicLength { 243 return false 244 } 245 246 for j, b := range bt { 247 if topic[j] != b { 248 return false 249 } 250 } 251 return true 252 } 253 254 // IsPubKeyEqual checks that two public keys are equal 255 func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool { 256 if !ValidatePublicKey(a) { 257 return false 258 } else if !ValidatePublicKey(b) { 259 return false 260 } 261 // the curve is always the same, just compare the points 262 return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0 263 }