github.com/status-im/status-go@v1.1.0/protocol/v1/status_message.go (about)

     1  package protocol
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"encoding/json"
     6  
     7  	"github.com/golang/protobuf/proto"
     8  	"github.com/jinzhu/copier"
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/ethereum/go-ethereum/common/hexutil"
    12  	"github.com/ethereum/go-ethereum/log"
    13  	utils "github.com/status-im/status-go/common"
    14  	"github.com/status-im/status-go/eth-node/crypto"
    15  	"github.com/status-im/status-go/eth-node/types"
    16  	"github.com/status-im/status-go/protocol/encryption"
    17  	"github.com/status-im/status-go/protocol/encryption/multidevice"
    18  	"github.com/status-im/status-go/protocol/encryption/sharedsecret"
    19  	"github.com/status-im/status-go/protocol/protobuf"
    20  )
    21  
    22  // TransportLayer is the lowest layer and represents waku message.
    23  type TransportLayer struct {
    24  	// Payload as received from the transport layer
    25  	Payload   []byte           `json:"-"`
    26  	Hash      []byte           `json:"-"`
    27  	SigPubKey *ecdsa.PublicKey `json:"-"`
    28  	Dst       *ecdsa.PublicKey
    29  	Message   *types.Message `json:"message"`
    30  }
    31  
    32  // EncryptionLayer handles optional encryption.
    33  // It is not mandatory and can be omitted,
    34  // also its presence does not guarantee encryption.
    35  type EncryptionLayer struct {
    36  	// Payload after having been processed by the encryption layer
    37  	Payload         []byte `json:"-"`
    38  	Installations   []*multidevice.Installation
    39  	SharedSecrets   []*sharedsecret.Secret
    40  	HashRatchetInfo []*encryption.HashRatchetInfo
    41  }
    42  
    43  // ApplicationLayer is the topmost layer and represents the application message.
    44  type ApplicationLayer struct {
    45  	// Payload after having been unwrapped from the application layer
    46  	Payload   []byte                                   `json:"-"`
    47  	ID        types.HexBytes                           `json:"id"`
    48  	SigPubKey *ecdsa.PublicKey                         `json:"-"`
    49  	Type      protobuf.ApplicationMetadataMessage_Type `json:"-"`
    50  }
    51  
    52  // StatusMessage encapsulates all layers of the protocol
    53  type StatusMessage struct {
    54  	TransportLayer   TransportLayer   `json:"transportLayer"`
    55  	EncryptionLayer  EncryptionLayer  `json:"encryptionLayer"`
    56  	ApplicationLayer ApplicationLayer `json:"applicationLayer"`
    57  }
    58  
    59  // Temporary JSON marshaling for those messages that are not yet processed
    60  // by the go code
    61  func (m *StatusMessage) MarshalJSON() ([]byte, error) {
    62  	item := struct {
    63  		ID        types.HexBytes `json:"id"`
    64  		Payload   string         `json:"payload"`
    65  		From      types.HexBytes `json:"from"`
    66  		Timestamp uint32         `json:"timestamp"`
    67  	}{
    68  		ID:        m.ApplicationLayer.ID,
    69  		Payload:   string(m.ApplicationLayer.Payload),
    70  		Timestamp: m.TransportLayer.Message.Timestamp,
    71  		From:      m.TransportLayer.Message.Sig,
    72  	}
    73  	return json.Marshal(item)
    74  }
    75  
    76  // SigPubKey returns the most important signature, from the application layer to transport
    77  func (m *StatusMessage) SigPubKey() *ecdsa.PublicKey {
    78  	if m.ApplicationLayer.SigPubKey != nil {
    79  		return m.ApplicationLayer.SigPubKey
    80  	}
    81  
    82  	return m.TransportLayer.SigPubKey
    83  }
    84  
    85  func (m *StatusMessage) Clone() (*StatusMessage, error) {
    86  	copy := &StatusMessage{}
    87  
    88  	err := copier.Copy(&copy, m)
    89  	return copy, err
    90  }
    91  
    92  func (m *StatusMessage) HandleTransportLayer(wakuMessage *types.Message) error {
    93  	publicKey, err := crypto.UnmarshalPubkey(wakuMessage.Sig)
    94  	if err != nil {
    95  		return errors.Wrap(err, "failed to get signature")
    96  	}
    97  
    98  	m.TransportLayer.Message = wakuMessage
    99  	m.TransportLayer.Hash = wakuMessage.Hash
   100  	m.TransportLayer.SigPubKey = publicKey
   101  	m.TransportLayer.Payload = wakuMessage.Payload
   102  
   103  	if wakuMessage.Dst != nil {
   104  		publicKey, err := crypto.UnmarshalPubkey(wakuMessage.Dst)
   105  		if err != nil {
   106  			return err
   107  		}
   108  		m.TransportLayer.Dst = publicKey
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  func (m *StatusMessage) HandleEncryptionLayer(myKey *ecdsa.PrivateKey, senderKey *ecdsa.PublicKey, enc *encryption.Protocol, skipNegotiation bool) error {
   115  	// As we handle non-encrypted messages, we make sure that DecryptPayload
   116  	// is set regardless of whether this step is successful
   117  	m.EncryptionLayer.Payload = m.TransportLayer.Payload
   118  	// Nothing to do
   119  	if skipNegotiation {
   120  		return nil
   121  	}
   122  
   123  	var protocolMessage encryption.ProtocolMessage
   124  	err := proto.Unmarshal(m.TransportLayer.Payload, &protocolMessage)
   125  	if err != nil {
   126  		return errors.Wrap(err, "failed to unmarshal ProtocolMessage")
   127  	}
   128  
   129  	response, err := enc.HandleMessage(
   130  		myKey,
   131  		senderKey,
   132  		&protocolMessage,
   133  		m.TransportLayer.Hash,
   134  	)
   135  
   136  	if err == encryption.ErrHashRatchetGroupIDNotFound {
   137  
   138  		if response != nil {
   139  			m.EncryptionLayer.HashRatchetInfo = response.HashRatchetInfo
   140  		}
   141  		return err
   142  	}
   143  
   144  	if err != nil {
   145  		return errors.Wrap(err, "failed to handle Encryption message")
   146  	}
   147  
   148  	m.EncryptionLayer.Payload = response.DecryptedMessage
   149  	m.EncryptionLayer.Installations = response.Installations
   150  	m.EncryptionLayer.SharedSecrets = response.SharedSecrets
   151  	m.EncryptionLayer.HashRatchetInfo = response.HashRatchetInfo
   152  	return nil
   153  }
   154  
   155  func (m *StatusMessage) HandleApplicationLayer() error {
   156  
   157  	message, err := protobuf.Unmarshal(m.EncryptionLayer.Payload)
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	recoveredKey, err := utils.RecoverKey(message)
   163  	if err != nil {
   164  		return err
   165  	}
   166  	m.ApplicationLayer.SigPubKey = recoveredKey
   167  	// Calculate ID using the wrapped record
   168  	m.ApplicationLayer.ID = MessageID(recoveredKey, m.EncryptionLayer.Payload)
   169  	log.Debug("calculated ID for envelope", "envelopeHash", hexutil.Encode(m.TransportLayer.Hash), "messageId", hexutil.Encode(m.ApplicationLayer.ID))
   170  
   171  	m.ApplicationLayer.Payload = message.Payload
   172  	m.ApplicationLayer.Type = message.Type
   173  	return nil
   174  
   175  }