mailserver.go 4.9 KB

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