github.com/luckypickle/go-ethereum-vet@v1.14.2/whisper/mailserver/mailserver.go (about) 1 // Copyright 2017 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 mailserver 18 19 import ( 20 "encoding/binary" 21 "fmt" 22 23 "github.com/luckypickle/go-ethereum-vet/common" 24 "github.com/luckypickle/go-ethereum-vet/crypto" 25 "github.com/luckypickle/go-ethereum-vet/log" 26 "github.com/luckypickle/go-ethereum-vet/rlp" 27 whisper "github.com/luckypickle/go-ethereum-vet/whisper/whisperv6" 28 "github.com/syndtr/goleveldb/leveldb" 29 "github.com/syndtr/goleveldb/leveldb/util" 30 ) 31 32 type WMailServer struct { 33 db *leveldb.DB 34 w *whisper.Whisper 35 pow float64 36 key []byte 37 } 38 39 type DBKey struct { 40 timestamp uint32 41 hash common.Hash 42 raw []byte 43 } 44 45 func NewDbKey(t uint32, h common.Hash) *DBKey { 46 const sz = common.HashLength + 4 47 var k DBKey 48 k.timestamp = t 49 k.hash = h 50 k.raw = make([]byte, sz) 51 binary.BigEndian.PutUint32(k.raw, k.timestamp) 52 copy(k.raw[4:], k.hash[:]) 53 return &k 54 } 55 56 func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, pow float64) error { 57 var err error 58 if len(path) == 0 { 59 return fmt.Errorf("DB file is not specified") 60 } 61 62 if len(password) == 0 { 63 return fmt.Errorf("password is not specified") 64 } 65 66 s.db, err = leveldb.OpenFile(path, nil) 67 if err != nil { 68 return fmt.Errorf("open DB file: %s", err) 69 } 70 71 s.w = shh 72 s.pow = pow 73 74 MailServerKeyID, err := s.w.AddSymKeyFromPassword(password) 75 if err != nil { 76 return fmt.Errorf("create symmetric key: %s", err) 77 } 78 s.key, err = s.w.GetSymKey(MailServerKeyID) 79 if err != nil { 80 return fmt.Errorf("save symmetric key: %s", err) 81 } 82 return nil 83 } 84 85 func (s *WMailServer) Close() { 86 if s.db != nil { 87 s.db.Close() 88 } 89 } 90 91 func (s *WMailServer) Archive(env *whisper.Envelope) { 92 key := NewDbKey(env.Expiry-env.TTL, env.Hash()) 93 rawEnvelope, err := rlp.EncodeToBytes(env) 94 if err != nil { 95 log.Error(fmt.Sprintf("rlp.EncodeToBytes failed: %s", err)) 96 } else { 97 err = s.db.Put(key.raw, rawEnvelope, nil) 98 if err != nil { 99 log.Error(fmt.Sprintf("Writing to DB failed: %s", err)) 100 } 101 } 102 } 103 104 func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) { 105 if peer == nil { 106 log.Error("Whisper peer is nil") 107 return 108 } 109 110 ok, lower, upper, bloom := s.validateRequest(peer.ID(), request) 111 if ok { 112 s.processRequest(peer, lower, upper, bloom) 113 } 114 } 115 116 func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, bloom []byte) []*whisper.Envelope { 117 ret := make([]*whisper.Envelope, 0) 118 var err error 119 var zero common.Hash 120 kl := NewDbKey(lower, zero) 121 ku := NewDbKey(upper, zero) 122 i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil) 123 defer i.Release() 124 125 for i.Next() { 126 var envelope whisper.Envelope 127 err = rlp.DecodeBytes(i.Value(), &envelope) 128 if err != nil { 129 log.Error(fmt.Sprintf("RLP decoding failed: %s", err)) 130 } 131 132 if whisper.BloomFilterMatch(bloom, envelope.Bloom()) { 133 if peer == nil { 134 // used for test purposes 135 ret = append(ret, &envelope) 136 } else { 137 err = s.w.SendP2PDirect(peer, &envelope) 138 if err != nil { 139 log.Error(fmt.Sprintf("Failed to send direct message to peer: %s", err)) 140 return nil 141 } 142 } 143 } 144 } 145 146 err = i.Error() 147 if err != nil { 148 log.Error(fmt.Sprintf("Level DB iterator error: %s", err)) 149 } 150 151 return ret 152 } 153 154 func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, []byte) { 155 if s.pow > 0.0 && request.PoW() < s.pow { 156 return false, 0, 0, nil 157 } 158 159 f := whisper.Filter{KeySym: s.key} 160 decrypted := request.Open(&f) 161 if decrypted == nil { 162 log.Warn(fmt.Sprintf("Failed to decrypt p2p request")) 163 return false, 0, 0, nil 164 } 165 166 src := crypto.FromECDSAPub(decrypted.Src) 167 if len(src)-len(peerID) == 1 { 168 src = src[1:] 169 } 170 171 // if you want to check the signature, you can do it here. e.g.: 172 // if !bytes.Equal(peerID, src) { 173 if src == nil { 174 log.Warn(fmt.Sprintf("Wrong signature of p2p request")) 175 return false, 0, 0, nil 176 } 177 178 var bloom []byte 179 payloadSize := len(decrypted.Payload) 180 if payloadSize < 8 { 181 log.Warn(fmt.Sprintf("Undersized p2p request")) 182 return false, 0, 0, nil 183 } else if payloadSize == 8 { 184 bloom = whisper.MakeFullNodeBloom() 185 } else if payloadSize < 8+whisper.BloomFilterSize { 186 log.Warn(fmt.Sprintf("Undersized bloom filter in p2p request")) 187 return false, 0, 0, nil 188 } else { 189 bloom = decrypted.Payload[8 : 8+whisper.BloomFilterSize] 190 } 191 192 lower := binary.BigEndian.Uint32(decrypted.Payload[:4]) 193 upper := binary.BigEndian.Uint32(decrypted.Payload[4:8]) 194 return true, lower, upper, bloom 195 }