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