github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/whisper/mailserver/mailserver.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-ethereum 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package mailserver
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  
    23  	"github.com/atheioschain/go-atheios/cmd/utils"
    24  	"github.com/atheioschain/go-atheios/common"
    25  	"github.com/atheioschain/go-atheios/crypto"
    26  	"github.com/atheioschain/go-atheios/logger"
    27  	"github.com/atheioschain/go-atheios/logger/glog"
    28  	"github.com/atheioschain/go-atheios/rlp"
    29  	whisper "github.com/atheioschain/go-atheios/whisper/whisperv5"
    30  	"github.com/syndtr/goleveldb/leveldb"
    31  	"github.com/syndtr/goleveldb/leveldb/util"
    32  )
    33  
    34  const MailServerKeyName = "958e04ab302fb36ad2616a352cbac79d"
    35  
    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  func NewDbKey(t uint32, h common.Hash) *DBKey {
    50  	const sz = common.HashLength + 4
    51  	var k DBKey
    52  	k.timestamp = t
    53  	k.hash = h
    54  	k.raw = make([]byte, sz)
    55  	binary.BigEndian.PutUint32(k.raw, k.timestamp)
    56  	copy(k.raw[4:], k.hash[:])
    57  	return &k
    58  }
    59  
    60  func (s *WMailServer) Init(shh *whisper.Whisper, path string, password string, pow float64) {
    61  	var err error
    62  	if len(path) == 0 {
    63  		utils.Fatalf("DB file is not specified")
    64  	}
    65  
    66  	if len(password) == 0 {
    67  		utils.Fatalf("Password is not specified for MailServer")
    68  	}
    69  
    70  	s.db, err = leveldb.OpenFile(path, nil)
    71  	if err != nil {
    72  		utils.Fatalf("Failed to open DB file: %s", err)
    73  	}
    74  
    75  	s.w = shh
    76  	s.pow = pow
    77  
    78  	err = s.w.AddSymKey(MailServerKeyName, []byte(password))
    79  	if err != nil {
    80  		utils.Fatalf("Failed to create symmetric key for MailServer: %s", err)
    81  	}
    82  	s.key = s.w.GetSymKey(MailServerKeyName)
    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  		glog.V(logger.Error).Infof("rlp.EncodeToBytes failed: %s", err)
    96  	} else {
    97  		err = s.db.Put(key.raw, rawEnvelope, nil)
    98  		if err != nil {
    99  			glog.V(logger.Error).Infof("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  		glog.V(logger.Error).Info("Whisper peer is nil")
   107  		return
   108  	}
   109  
   110  	ok, lower, upper, topic := s.validateRequest(peer.ID(), request)
   111  	if ok {
   112  		s.processRequest(peer, lower, upper, topic)
   113  	}
   114  }
   115  
   116  func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, topic whisper.TopicType) []*whisper.Envelope {
   117  	ret := make([]*whisper.Envelope, 0)
   118  	var err error
   119  	var zero common.Hash
   120  	var empty whisper.TopicType
   121  	kl := NewDbKey(lower, zero)
   122  	ku := NewDbKey(upper, zero)
   123  	i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil)
   124  	defer i.Release()
   125  
   126  	for i.Next() {
   127  		var envelope whisper.Envelope
   128  		err = rlp.DecodeBytes(i.Value(), &envelope)
   129  		if err != nil {
   130  			glog.V(logger.Error).Infof("RLP decoding failed: %s", err)
   131  		}
   132  
   133  		if topic == empty || envelope.Topic == topic {
   134  			if peer == nil {
   135  				// used for test purposes
   136  				ret = append(ret, &envelope)
   137  			} else {
   138  				err = s.w.SendP2PDirect(peer, &envelope)
   139  				if err != nil {
   140  					glog.V(logger.Error).Infof("Failed to send direct message to peer: %s", err)
   141  					return nil
   142  				}
   143  			}
   144  		}
   145  	}
   146  
   147  	err = i.Error()
   148  	if err != nil {
   149  		glog.V(logger.Error).Infof("Level DB iterator error: %s", err)
   150  	}
   151  
   152  	return ret
   153  }
   154  
   155  func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, whisper.TopicType) {
   156  	var topic whisper.TopicType
   157  	if s.pow > 0.0 && request.PoW() < s.pow {
   158  		return false, 0, 0, topic
   159  	}
   160  
   161  	f := whisper.Filter{KeySym: s.key}
   162  	decrypted := request.Open(&f)
   163  	if decrypted == nil {
   164  		glog.V(logger.Warn).Infof("Failed to decrypt p2p request")
   165  		return false, 0, 0, topic
   166  	}
   167  
   168  	if len(decrypted.Payload) < 8 {
   169  		glog.V(logger.Warn).Infof("Undersized p2p request")
   170  		return false, 0, 0, topic
   171  	}
   172  
   173  	src := crypto.FromECDSAPub(decrypted.Src)
   174  	if len(src)-len(peerID) == 1 {
   175  		src = src[1:]
   176  	}
   177  	if !bytes.Equal(peerID, src) {
   178  		glog.V(logger.Warn).Infof("Wrong signature of p2p request")
   179  		return false, 0, 0, topic
   180  	}
   181  
   182  	lower := binary.BigEndian.Uint32(decrypted.Payload[:4])
   183  	upper := binary.BigEndian.Uint32(decrypted.Payload[4:8])
   184  
   185  	if len(decrypted.Payload) >= 8+whisper.TopicLength {
   186  		topic = whisper.BytesToTopic(decrypted.Payload[8:])
   187  	}
   188  
   189  	return true, lower, upper, topic
   190  }