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(©, 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 }