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