github.com/fxsjy/go-ethereum@v1.8.4-0.20180410143526-2e247705cd27/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/ethereum/go-ethereum/cmd/utils" 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/crypto" 26 "github.com/ethereum/go-ethereum/log" 27 "github.com/ethereum/go-ethereum/rlp" 28 whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" 29 "github.com/syndtr/goleveldb/leveldb" 30 "github.com/syndtr/goleveldb/leveldb/util" 31 ) 32 33 type WMailServer struct { 34 db *leveldb.DB 35 w *whisper.Whisper 36 pow float64 37 key []byte 38 } 39 40 type DBKey struct { 41 timestamp uint32 42 hash common.Hash 43 raw []byte 44 } 45 46 func NewDbKey(t uint32, h common.Hash) *DBKey { 47 const sz = common.HashLength + 4 48 var k DBKey 49 k.timestamp = t 50 k.hash = h 51 k.raw = make([]byte, sz) 52 binary.BigEndian.PutUint32(k.raw, k.timestamp) 53 copy(k.raw[4:], k.hash[:]) 54 return &k 55 } 56 57 func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, pow float64) { 58 var err error 59 if len(path) == 0 { 60 utils.Fatalf("DB file is not specified") 61 } 62 63 if len(password) == 0 { 64 utils.Fatalf("Password is not specified for MailServer") 65 } 66 67 s.db, err = leveldb.OpenFile(path, nil) 68 if err != nil { 69 utils.Fatalf("Failed to open DB file: %s", err) 70 } 71 72 s.w = shh 73 s.pow = pow 74 75 MailServerKeyID, err := s.w.AddSymKeyFromPassword(password) 76 if err != nil { 77 utils.Fatalf("Failed to create symmetric key for MailServer: %s", err) 78 } 79 s.key, err = s.w.GetSymKey(MailServerKeyID) 80 if err != nil { 81 utils.Fatalf("Failed to save symmetric key for MailServer") 82 } 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 }