github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/whisperv6/api.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:51</date>
    10  //</624342689814417408>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package whisperv6
    29  
    30  import (
    31  	"context"
    32  	"crypto/ecdsa"
    33  	"errors"
    34  	"fmt"
    35  	"sync"
    36  	"time"
    37  
    38  	"github.com/ethereum/go-ethereum/common"
    39  	"github.com/ethereum/go-ethereum/common/hexutil"
    40  	"github.com/ethereum/go-ethereum/crypto"
    41  	"github.com/ethereum/go-ethereum/log"
    42  	"github.com/ethereum/go-ethereum/p2p/discover"
    43  	"github.com/ethereum/go-ethereum/rpc"
    44  )
    45  
    46  //
    47  var (
    48  	ErrSymAsym              = errors.New("specify either a symmetric or an asymmetric key")
    49  	ErrInvalidSymmetricKey  = errors.New("invalid symmetric key")
    50  	ErrInvalidPublicKey     = errors.New("invalid public key")
    51  	ErrInvalidSigningPubKey = errors.New("invalid signing public key")
    52  	ErrTooLowPoW            = errors.New("message rejected, PoW too low")
    53  	ErrNoTopics             = errors.New("missing topic(s)")
    54  )
    55  
    56  //
    57  //
    58  type PublicWhisperAPI struct {
    59  	w *Whisper
    60  
    61  	mu       sync.Mutex
    62  lastUsed map[string]time.Time //
    63  }
    64  
    65  //
    66  func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI {
    67  	api := &PublicWhisperAPI{
    68  		w:        w,
    69  		lastUsed: make(map[string]time.Time),
    70  	}
    71  	return api
    72  }
    73  
    74  //
    75  func (api *PublicWhisperAPI) Version(ctx context.Context) string {
    76  	return ProtocolVersionStr
    77  }
    78  
    79  //
    80  type Info struct {
    81  Memory         int     `json:"memory"`         //
    82  Messages       int     `json:"messages"`       //
    83  MinPow         float64 `json:"minPow"`         //
    84  MaxMessageSize uint32  `json:"maxMessageSize"` //
    85  }
    86  
    87  //
    88  func (api *PublicWhisperAPI) Info(ctx context.Context) Info {
    89  	stats := api.w.Stats()
    90  	return Info{
    91  		Memory:         stats.memoryUsed,
    92  		Messages:       len(api.w.messageQueue) + len(api.w.p2pMsgQueue),
    93  		MinPow:         api.w.MinPow(),
    94  		MaxMessageSize: api.w.MaxMessageSize(),
    95  	}
    96  }
    97  
    98  //
    99  //
   100  func (api *PublicWhisperAPI) SetMaxMessageSize(ctx context.Context, size uint32) (bool, error) {
   101  	return true, api.w.SetMaxMessageSize(size)
   102  }
   103  
   104  //
   105  func (api *PublicWhisperAPI) SetMinPoW(ctx context.Context, pow float64) (bool, error) {
   106  	return true, api.w.SetMinimumPoW(pow)
   107  }
   108  
   109  //
   110  func (api *PublicWhisperAPI) SetBloomFilter(ctx context.Context, bloom hexutil.Bytes) (bool, error) {
   111  	return true, api.w.SetBloomFilter(bloom)
   112  }
   113  
   114  //
   115  //
   116  func (api *PublicWhisperAPI) MarkTrustedPeer(ctx context.Context, enode string) (bool, error) {
   117  	n, err := discover.ParseNode(enode)
   118  	if err != nil {
   119  		return false, err
   120  	}
   121  	return true, api.w.AllowP2PMessagesFromPeer(n.ID[:])
   122  }
   123  
   124  //
   125  //
   126  func (api *PublicWhisperAPI) NewKeyPair(ctx context.Context) (string, error) {
   127  	return api.w.NewKeyPair()
   128  }
   129  
   130  //
   131  func (api *PublicWhisperAPI) AddPrivateKey(ctx context.Context, privateKey hexutil.Bytes) (string, error) {
   132  	key, err := crypto.ToECDSA(privateKey)
   133  	if err != nil {
   134  		return "", err
   135  	}
   136  	return api.w.AddKeyPair(key)
   137  }
   138  
   139  //
   140  func (api *PublicWhisperAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error) {
   141  	if ok := api.w.DeleteKeyPair(key); ok {
   142  		return true, nil
   143  	}
   144  	return false, fmt.Errorf("key pair %s not found", key)
   145  }
   146  
   147  //
   148  func (api *PublicWhisperAPI) HasKeyPair(ctx context.Context, id string) bool {
   149  	return api.w.HasKeyPair(id)
   150  }
   151  
   152  //
   153  //
   154  func (api *PublicWhisperAPI) GetPublicKey(ctx context.Context, id string) (hexutil.Bytes, error) {
   155  	key, err := api.w.GetPrivateKey(id)
   156  	if err != nil {
   157  		return hexutil.Bytes{}, err
   158  	}
   159  	return crypto.FromECDSAPub(&key.PublicKey), nil
   160  }
   161  
   162  //
   163  //
   164  func (api *PublicWhisperAPI) GetPrivateKey(ctx context.Context, id string) (hexutil.Bytes, error) {
   165  	key, err := api.w.GetPrivateKey(id)
   166  	if err != nil {
   167  		return hexutil.Bytes{}, err
   168  	}
   169  	return crypto.FromECDSA(key), nil
   170  }
   171  
   172  //
   173  //
   174  //
   175  func (api *PublicWhisperAPI) NewSymKey(ctx context.Context) (string, error) {
   176  	return api.w.GenerateSymKey()
   177  }
   178  
   179  //
   180  //
   181  //
   182  func (api *PublicWhisperAPI) AddSymKey(ctx context.Context, key hexutil.Bytes) (string, error) {
   183  	return api.w.AddSymKeyDirect([]byte(key))
   184  }
   185  
   186  //
   187  func (api *PublicWhisperAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) {
   188  	return api.w.AddSymKeyFromPassword(passwd)
   189  }
   190  
   191  //
   192  func (api *PublicWhisperAPI) HasSymKey(ctx context.Context, id string) bool {
   193  	return api.w.HasSymKey(id)
   194  }
   195  
   196  //
   197  func (api *PublicWhisperAPI) GetSymKey(ctx context.Context, id string) (hexutil.Bytes, error) {
   198  	return api.w.GetSymKey(id)
   199  }
   200  
   201  //
   202  func (api *PublicWhisperAPI) DeleteSymKey(ctx context.Context, id string) bool {
   203  	return api.w.DeleteSymKey(id)
   204  }
   205  
   206  //
   207  //
   208  func (api *PublicWhisperAPI) MakeLightClient(ctx context.Context) bool {
   209  	api.w.lightClient = true
   210  	return api.w.lightClient
   211  }
   212  
   213  //
   214  func (api *PublicWhisperAPI) CancelLightClient(ctx context.Context) bool {
   215  	api.w.lightClient = false
   216  	return !api.w.lightClient
   217  }
   218  
   219  //
   220  
   221  //
   222  type NewMessage struct {
   223  	SymKeyID   string    `json:"symKeyID"`
   224  	PublicKey  []byte    `json:"pubKey"`
   225  	Sig        string    `json:"sig"`
   226  	TTL        uint32    `json:"ttl"`
   227  	Topic      TopicType `json:"topic"`
   228  	Payload    []byte    `json:"payload"`
   229  	Padding    []byte    `json:"padding"`
   230  	PowTime    uint32    `json:"powTime"`
   231  	PowTarget  float64   `json:"powTarget"`
   232  	TargetPeer string    `json:"targetPeer"`
   233  }
   234  
   235  type newMessageOverride struct {
   236  	PublicKey hexutil.Bytes
   237  	Payload   hexutil.Bytes
   238  	Padding   hexutil.Bytes
   239  }
   240  
   241  //
   242  //
   243  func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil.Bytes, error) {
   244  	var (
   245  		symKeyGiven = len(req.SymKeyID) > 0
   246  		pubKeyGiven = len(req.PublicKey) > 0
   247  		err         error
   248  	)
   249  
   250  //
   251  	if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) {
   252  		return nil, ErrSymAsym
   253  	}
   254  
   255  	params := &MessageParams{
   256  		TTL:      req.TTL,
   257  		Payload:  req.Payload,
   258  		Padding:  req.Padding,
   259  		WorkTime: req.PowTime,
   260  		PoW:      req.PowTarget,
   261  		Topic:    req.Topic,
   262  	}
   263  
   264  //
   265  	if len(req.Sig) > 0 {
   266  		if params.Src, err = api.w.GetPrivateKey(req.Sig); err != nil {
   267  			return nil, err
   268  		}
   269  	}
   270  
   271  //
   272  	if symKeyGiven {
   273  if params.Topic == (TopicType{}) { //
   274  			return nil, ErrNoTopics
   275  		}
   276  		if params.KeySym, err = api.w.GetSymKey(req.SymKeyID); err != nil {
   277  			return nil, err
   278  		}
   279  		if !validateDataIntegrity(params.KeySym, aesKeyLength) {
   280  			return nil, ErrInvalidSymmetricKey
   281  		}
   282  	}
   283  
   284  //
   285  	if pubKeyGiven {
   286  		if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
   287  			return nil, ErrInvalidPublicKey
   288  		}
   289  	}
   290  
   291  //
   292  	whisperMsg, err := NewSentMessage(params)
   293  	if err != nil {
   294  		return nil, err
   295  	}
   296  
   297  	var result []byte
   298  	env, err := whisperMsg.Wrap(params)
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  
   303  //
   304  	if len(req.TargetPeer) > 0 {
   305  		n, err := discover.ParseNode(req.TargetPeer)
   306  		if err != nil {
   307  			return nil, fmt.Errorf("failed to parse target peer: %s", err)
   308  		}
   309  		err = api.w.SendP2PMessage(n.ID[:], env)
   310  		if err == nil {
   311  			hash := env.Hash()
   312  			result = hash[:]
   313  		}
   314  		return result, err
   315  	}
   316  
   317  //
   318  	if req.PowTarget < api.w.MinPow() {
   319  		return nil, ErrTooLowPoW
   320  	}
   321  
   322  	err = api.w.Send(env)
   323  	if err == nil {
   324  		hash := env.Hash()
   325  		result = hash[:]
   326  	}
   327  	return result, err
   328  }
   329  
   330  //
   331  
   332  //
   333  type Criteria struct {
   334  	SymKeyID     string      `json:"symKeyID"`
   335  	PrivateKeyID string      `json:"privateKeyID"`
   336  	Sig          []byte      `json:"sig"`
   337  	MinPow       float64     `json:"minPow"`
   338  	Topics       []TopicType `json:"topics"`
   339  	AllowP2P     bool        `json:"allowP2P"`
   340  }
   341  
   342  type criteriaOverride struct {
   343  	Sig hexutil.Bytes
   344  }
   345  
   346  //
   347  //
   348  func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.Subscription, error) {
   349  	var (
   350  		symKeyGiven = len(crit.SymKeyID) > 0
   351  		pubKeyGiven = len(crit.PrivateKeyID) > 0
   352  		err         error
   353  	)
   354  
   355  //
   356  	notifier, supported := rpc.NotifierFromContext(ctx)
   357  	if !supported {
   358  		return nil, rpc.ErrNotificationsUnsupported
   359  	}
   360  
   361  //
   362  	if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) {
   363  		return nil, ErrSymAsym
   364  	}
   365  
   366  	filter := Filter{
   367  		PoW:      crit.MinPow,
   368  		Messages: make(map[common.Hash]*ReceivedMessage),
   369  		AllowP2P: crit.AllowP2P,
   370  	}
   371  
   372  	if len(crit.Sig) > 0 {
   373  		if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
   374  			return nil, ErrInvalidSigningPubKey
   375  		}
   376  	}
   377  
   378  	for i, bt := range crit.Topics {
   379  		if len(bt) == 0 || len(bt) > 4 {
   380  			return nil, fmt.Errorf("subscribe: topic %d has wrong size: %d", i, len(bt))
   381  		}
   382  		filter.Topics = append(filter.Topics, bt[:])
   383  	}
   384  
   385  //
   386  	if symKeyGiven {
   387  		if len(filter.Topics) == 0 {
   388  			return nil, ErrNoTopics
   389  		}
   390  		key, err := api.w.GetSymKey(crit.SymKeyID)
   391  		if err != nil {
   392  			return nil, err
   393  		}
   394  		if !validateDataIntegrity(key, aesKeyLength) {
   395  			return nil, ErrInvalidSymmetricKey
   396  		}
   397  		filter.KeySym = key
   398  		filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym)
   399  	}
   400  
   401  //
   402  	if pubKeyGiven {
   403  		filter.KeyAsym, err = api.w.GetPrivateKey(crit.PrivateKeyID)
   404  		if err != nil || filter.KeyAsym == nil {
   405  			return nil, ErrInvalidPublicKey
   406  		}
   407  	}
   408  
   409  	id, err := api.w.Subscribe(&filter)
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  
   414  //
   415  	rpcSub := notifier.CreateSubscription()
   416  	go func() {
   417  //
   418  		ticker := time.NewTicker(250 * time.Millisecond)
   419  		defer ticker.Stop()
   420  
   421  		for {
   422  			select {
   423  			case <-ticker.C:
   424  				if filter := api.w.GetFilter(id); filter != nil {
   425  					for _, rpcMessage := range toMessage(filter.Retrieve()) {
   426  						if err := notifier.Notify(rpcSub.ID, rpcMessage); err != nil {
   427  							log.Error("Failed to send notification", "err", err)
   428  						}
   429  					}
   430  				}
   431  			case <-rpcSub.Err():
   432  				api.w.Unsubscribe(id)
   433  				return
   434  			case <-notifier.Closed():
   435  				api.w.Unsubscribe(id)
   436  				return
   437  			}
   438  		}
   439  	}()
   440  
   441  	return rpcSub, nil
   442  }
   443  
   444  //
   445  
   446  //
   447  type Message struct {
   448  	Sig       []byte    `json:"sig,omitempty"`
   449  	TTL       uint32    `json:"ttl"`
   450  	Timestamp uint32    `json:"timestamp"`
   451  	Topic     TopicType `json:"topic"`
   452  	Payload   []byte    `json:"payload"`
   453  	Padding   []byte    `json:"padding"`
   454  	PoW       float64   `json:"pow"`
   455  	Hash      []byte    `json:"hash"`
   456  	Dst       []byte    `json:"recipientPublicKey,omitempty"`
   457  }
   458  
   459  type messageOverride struct {
   460  	Sig     hexutil.Bytes
   461  	Payload hexutil.Bytes
   462  	Padding hexutil.Bytes
   463  	Hash    hexutil.Bytes
   464  	Dst     hexutil.Bytes
   465  }
   466  
   467  //
   468  func ToWhisperMessage(message *ReceivedMessage) *Message {
   469  	msg := Message{
   470  		Payload:   message.Payload,
   471  		Padding:   message.Padding,
   472  		Timestamp: message.Sent,
   473  		TTL:       message.TTL,
   474  		PoW:       message.PoW,
   475  		Hash:      message.EnvelopeHash.Bytes(),
   476  		Topic:     message.Topic,
   477  	}
   478  
   479  	if message.Dst != nil {
   480  		b := crypto.FromECDSAPub(message.Dst)
   481  		if b != nil {
   482  			msg.Dst = b
   483  		}
   484  	}
   485  
   486  	if isMessageSigned(message.Raw[0]) {
   487  		b := crypto.FromECDSAPub(message.SigToPubKey())
   488  		if b != nil {
   489  			msg.Sig = b
   490  		}
   491  	}
   492  
   493  	return &msg
   494  }
   495  
   496  //
   497  func toMessage(messages []*ReceivedMessage) []*Message {
   498  	msgs := make([]*Message, len(messages))
   499  	for i, msg := range messages {
   500  		msgs[i] = ToWhisperMessage(msg)
   501  	}
   502  	return msgs
   503  }
   504  
   505  //
   506  //
   507  func (api *PublicWhisperAPI) GetFilterMessages(id string) ([]*Message, error) {
   508  	api.mu.Lock()
   509  	f := api.w.GetFilter(id)
   510  	if f == nil {
   511  		api.mu.Unlock()
   512  		return nil, fmt.Errorf("filter not found")
   513  	}
   514  	api.lastUsed[id] = time.Now()
   515  	api.mu.Unlock()
   516  
   517  	receivedMessages := f.Retrieve()
   518  	messages := make([]*Message, 0, len(receivedMessages))
   519  	for _, msg := range receivedMessages {
   520  		messages = append(messages, ToWhisperMessage(msg))
   521  	}
   522  
   523  	return messages, nil
   524  }
   525  
   526  //
   527  func (api *PublicWhisperAPI) DeleteMessageFilter(id string) (bool, error) {
   528  	api.mu.Lock()
   529  	defer api.mu.Unlock()
   530  
   531  	delete(api.lastUsed, id)
   532  	return true, api.w.Unsubscribe(id)
   533  }
   534  
   535  //
   536  //
   537  func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
   538  	var (
   539  		src     *ecdsa.PublicKey
   540  		keySym  []byte
   541  		keyAsym *ecdsa.PrivateKey
   542  		topics  [][]byte
   543  
   544  		symKeyGiven  = len(req.SymKeyID) > 0
   545  		asymKeyGiven = len(req.PrivateKeyID) > 0
   546  
   547  		err error
   548  	)
   549  
   550  //
   551  	if (symKeyGiven && asymKeyGiven) || (!symKeyGiven && !asymKeyGiven) {
   552  		return "", ErrSymAsym
   553  	}
   554  
   555  	if len(req.Sig) > 0 {
   556  		if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
   557  			return "", ErrInvalidSigningPubKey
   558  		}
   559  	}
   560  
   561  	if symKeyGiven {
   562  		if keySym, err = api.w.GetSymKey(req.SymKeyID); err != nil {
   563  			return "", err
   564  		}
   565  		if !validateDataIntegrity(keySym, aesKeyLength) {
   566  			return "", ErrInvalidSymmetricKey
   567  		}
   568  	}
   569  
   570  	if asymKeyGiven {
   571  		if keyAsym, err = api.w.GetPrivateKey(req.PrivateKeyID); err != nil {
   572  			return "", err
   573  		}
   574  	}
   575  
   576  	if len(req.Topics) > 0 {
   577  		topics = make([][]byte, len(req.Topics))
   578  		for i, topic := range req.Topics {
   579  			topics[i] = make([]byte, TopicLength)
   580  			copy(topics[i], topic[:])
   581  		}
   582  	}
   583  
   584  	f := &Filter{
   585  		Src:      src,
   586  		KeySym:   keySym,
   587  		KeyAsym:  keyAsym,
   588  		PoW:      req.MinPow,
   589  		AllowP2P: req.AllowP2P,
   590  		Topics:   topics,
   591  		Messages: make(map[common.Hash]*ReceivedMessage),
   592  	}
   593  
   594  	id, err := api.w.Subscribe(f)
   595  	if err != nil {
   596  		return "", err
   597  	}
   598  
   599  	api.mu.Lock()
   600  	api.lastUsed[id] = time.Now()
   601  	api.mu.Unlock()
   602  
   603  	return id, nil
   604  }
   605