Skip to content

Commit

Permalink
Handle unencrypted message while getting messages with crypto (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
Xavrax authored Nov 27, 2023
1 parent 0b6f537 commit f5c19c1
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 14 deletions.
9 changes: 7 additions & 2 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
---
version: v7.2.0
version: v7.2.1
changelog:
- date: 2023-11-27
version: v7.2.1
changes:
- type: bug
text: "Handle unencrypted message while getting messages with crypto."
- date: 2023-10-16
version: v7.2.0
changes:
Expand Down Expand Up @@ -740,7 +745,7 @@ sdks:
distribution-type: package
distribution-repository: GitHub
package-name: Go
location: https://github.com/pubnub/go/releases/tag/v7.2.0
location: https://github.com/pubnub/go/releases/tag/v7.2.1
requires:
-
name: "Go"
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v7.2.1
November 27 2023

#### Fixed
- Handle unencrypted message while getting messages with crypto.

## v7.2.0
October 16 2023

Expand Down
5 changes: 5 additions & 0 deletions crypto/legacy_cryptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ func (c *legacyCryptor) Encrypt(message []byte) (*EncryptedData, error) {
func (c *legacyCryptor) Decrypt(encryptedData *EncryptedData) (r []byte, e error) {
iv := make([]byte, aes.BlockSize)
data := encryptedData.Data

if c.randomIv {
if (len(data) < aes.BlockSize) {
return nil, fmt.Errorf("length of data to decrypt should be at least %d", aes.BlockSize)
}

iv = data[:aes.BlockSize]
data = data[aes.BlockSize:]
} else {
Expand Down
5 changes: 4 additions & 1 deletion fetch_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,13 @@ func (o *fetchOpts) fetchMessages(channels map[string]interface{}) map[string][]

for _, val := range histResponseMap {
if histResponse, ok3 := val.(map[string]interface{}); ok3 {
msg, _ := parseCipherInterface(histResponse["message"], o.pubnub.Config, o.pubnub.getCryptoModule())
msg, err := parseCipherInterface(histResponse["message"], o.pubnub.Config, o.pubnub.getCryptoModule())

histItem := FetchResponseItem{
Message: msg,
Timetoken: histResponse["timetoken"].(string),
Meta: histResponse["meta"],
Error: err,
}
if d, ok := histResponse["message_type"]; ok {
switch v := d.(type) {
Expand Down Expand Up @@ -385,6 +386,7 @@ type FetchResponse struct {
}

// FetchResponseItem contains the message and the associated timetoken.
// It can contain the error if the message is not decrypted properly assuming the message is not encrypted.
type FetchResponseItem struct {
Message interface{} `json:"message"`
Meta interface{} `json:"meta"`
Expand All @@ -393,6 +395,7 @@ type FetchResponseItem struct {
Timetoken string `json:"timetoken"`
UUID string `json:"uuid"`
MessageType int `json:"message_type"`
Error error
}

// PNHistoryMessageActionsTypeMap is the struct used in the Fetch request that includes Message Actions
Expand Down
5 changes: 3 additions & 2 deletions history_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ type HistoryResponseItem struct {
Message interface{}
Meta interface{}
Timetoken int64
Error error
}

func logAndCreateNewResponseParsingError(o *historyOpts, err error, jsonBody string, message string) *pnerr.ResponseParsingError {
Expand All @@ -224,7 +225,7 @@ func getHistoryItemsWithoutTimetoken(historyResponseRaw []byte, o *historyOpts,

for i, v := range historyResponseItems {
o.pubnub.Config.Log.Println(v)
items[i].Message, _ = parseCipherInterface(v, o.pubnub.Config, o.pubnub.getCryptoModule())
items[i].Message, items[i].Error = parseCipherInterface(v, o.pubnub.Config, o.pubnub.getCryptoModule())
}
return items, nil
}
Expand All @@ -237,7 +238,7 @@ func getHistoryItemsWithTimetoken(historyResponseItems []HistoryResponseItem, o
for i, v := range historyResponseItems {
if v.Message != nil {
o.pubnub.Config.Log.Println(v.Message)
items[i].Message, _ = parseCipherInterface(v.Message, o.pubnub.Config, o.pubnub.getCryptoModule())
items[i].Message, items[i].Error = parseCipherInterface(v.Message, o.pubnub.Config, o.pubnub.getCryptoModule())

o.pubnub.Config.Log.Println(v.Timetoken)
items[i].Timetoken = v.Timetoken
Expand Down
45 changes: 45 additions & 0 deletions history_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"testing"

"github.com/pubnub/go/v7/crypto"
h "github.com/pubnub/go/v7/tests/helpers"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -425,6 +426,7 @@ func TestHistoryEncrypt(t *testing.T) {

messages := resp.Messages
assert.Equal("hey", messages[0].Message)
assert.Nil(messages[0].Error)
pnconfig.CipherKey = ""
}

Expand Down Expand Up @@ -550,5 +552,48 @@ func TestHistoryResponseEndTTError(t *testing.T) {
assert.Equal(int64(121324), resp.StartTimetoken)
assert.Equal(int64(0), resp.EndTimetoken)
assert.Nil(err)
}

func TestHistoryCryptoModuleWithEncryptedMessage(t *testing.T) {
assert := assert.New(t)
pnconfig := NewDemoConfig()
pubnub := NewPubNub(pnconfig)
crypto, init_err := crypto.NewAesCbcCryptoModule("enigma", true)

assert.Nil(init_err)

pubnub.Config.CryptoModule = crypto

// Rust generated cipher text
jsonString := []byte(`[["UE5FRAFBQ1JIEALf+E65kseYJwTw2J6BUk9MePHiCcBCS+8ykXLkBIOA"],14991775432719844,14991868111600528]`)

resp, _, err := newHistoryResponse(jsonString, pubnub.initHistoryOpts(), fakeResponseState)
assert.Nil(err)

messages := resp.Messages
assert.Equal("test", messages[0].Message)
assert.Nil(messages[0].Error)
pnconfig.CipherKey = ""
}

func TestHistoryCryptoModuleWithNoEncryptedMessage(t *testing.T) {
assert := assert.New(t)
pnconfig := NewDemoConfig()
pubnub := NewPubNub(pnconfig)
crypto, init_err := crypto.NewAesCbcCryptoModule("enigma", true)

assert.Nil(init_err)

pubnub.Config.CryptoModule = crypto

jsonString := []byte(`[["test"],14991775432719844,14991868111600528]`)

resp, _, err := newHistoryResponse(jsonString, pubnub.initHistoryOpts(), fakeResponseState)
assert.Nil(err)

messages := resp.Messages
assert.Equal("test", messages[0].Message)
assert.NotNil(messages[0].Error)
pnconfig.CipherKey = ""
}

2 changes: 2 additions & 0 deletions listener_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ type PNMessage struct {
Subscription string
Publisher string
Timetoken int64
Error error
}

// PNPresence is the Message Response for Presence
Expand Down Expand Up @@ -360,4 +361,5 @@ type PNFilesEvent struct {
Subscription string
Publisher string
Timetoken int64
Error error
}
2 changes: 1 addition & 1 deletion pubnub.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
// Default constants
const (
// Version :the version of the SDK
Version = "7.2.0"
Version = "7.2.1"
// MaxSequence for publish messages
MaxSequence = 65535
)
Expand Down
19 changes: 11 additions & 8 deletions subscription_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ func processNonPresencePayload(m *SubscriptionManager, payload subscribeMessage,

switch payload.MessageType {
case PNMessageTypeSignal:
pnMessageResult := createPNMessageResult(payload.Payload, actualCh, subscribedCh, channel, subscriptionMatch, payload.IssuingClientID, payload.UserMetadata, timetoken)
pnMessageResult := createPNMessageResult(payload.Payload, actualCh, subscribedCh, channel, subscriptionMatch, payload.IssuingClientID, payload.UserMetadata, timetoken, /*no error*/nil)
m.pubnub.Config.Log.Println("announceSignal,", pnMessageResult)
m.listenerManager.announceSignal(pnMessageResult)
case PNMessageTypeObjects:
Expand Down Expand Up @@ -675,7 +675,7 @@ func processNonPresencePayload(m *SubscriptionManager, payload subscribeMessage,

}

pnFilesEvent := createPNFilesEvent(messagePayload, m, actualCh, subscribedCh, channel, subscriptionMatch, payload.IssuingClientID, payload.UserMetadata, timetoken)
pnFilesEvent := createPNFilesEvent(messagePayload, m, actualCh, subscribedCh, channel, subscriptionMatch, payload.IssuingClientID, payload.UserMetadata, timetoken, err)
m.pubnub.Config.Log.Println("PNMessageTypeFile:", PNMessageTypeFile)
m.listenerManager.announceFile(pnFilesEvent)
default:
Expand All @@ -693,7 +693,7 @@ func processNonPresencePayload(m *SubscriptionManager, payload subscribeMessage,
m.listenerManager.announceStatus(pnStatus)

}
pnMessageResult := createPNMessageResult(messagePayload, actualCh, subscribedCh, channel, subscriptionMatch, payload.IssuingClientID, payload.UserMetadata, timetoken)
pnMessageResult := createPNMessageResult(messagePayload, actualCh, subscribedCh, channel, subscriptionMatch, payload.IssuingClientID, payload.UserMetadata, timetoken, err)
m.pubnub.Config.Log.Println("announceMessage,", pnMessageResult)
m.listenerManager.announceMessage(pnMessageResult)
}
Expand All @@ -716,7 +716,7 @@ func processSubscribePayload(m *SubscriptionManager, payload subscribeMessage) {
}
}

func createPNFilesEvent(filePayload interface{}, m *SubscriptionManager, actualCh, subscribedCh, channel, subscriptionMatch, issuingClientID string, userMetadata interface{}, timetoken int64) *PNFilesEvent {
func createPNFilesEvent(filePayload interface{}, m *SubscriptionManager, actualCh, subscribedCh, channel, subscriptionMatch, issuingClientID string, userMetadata interface{}, timetoken int64, err error) *PNFilesEvent {
var filesPayload map[string]interface{}
var ok bool
if filesPayload, ok = filePayload.(map[string]interface{}); !ok {
Expand Down Expand Up @@ -747,6 +747,7 @@ func createPNFilesEvent(filePayload interface{}, m *SubscriptionManager, actualC
Timetoken: timetoken,
Publisher: issuingClientID,
UserMetadata: userMetadata,
Error: err,
}
return pnFilesEvent
}
Expand Down Expand Up @@ -933,7 +934,7 @@ func createPNObjectsResult(objPayload interface{}, m *SubscriptionManager, actua
return pnUUIDEvent, pnChannelEvent, pnMembershipEvent, eventType
}

func createPNMessageResult(messagePayload interface{}, actualCh, subscribedCh, channel, subscriptionMatch, issuingClientID string, userMetadata interface{}, timetoken int64) *PNMessage {
func createPNMessageResult(messagePayload interface{}, actualCh, subscribedCh, channel, subscriptionMatch, issuingClientID string, userMetadata interface{}, timetoken int64, error error) *PNMessage {

pnMessageResult := &PNMessage{
Message: messagePayload,
Expand All @@ -944,10 +945,10 @@ func createPNMessageResult(messagePayload interface{}, actualCh, subscribedCh, c
Timetoken: timetoken,
Publisher: issuingClientID,
UserMetadata: userMetadata,
Error: error,
}

return pnMessageResult

}

// parseCipherInterface handles the decryption in case a cipher key is used
Expand All @@ -971,7 +972,8 @@ func parseCipherInterface(data interface{}, pnConf *Config, module crypto.Crypto
pnConf.Log.Println("v[pn_other]", v["pn_other"], v, msg)
decrypted, errDecryption := decryptString(module, msg)
if errDecryption != nil {
pnConf.Log.Println(errDecryption, msg)
pnConf.Log.Println(errDecryption, msg, "\nMessage might be not encrypted, returning as is...")

return v, errDecryption
} else {
var intf interface{}
Expand All @@ -994,7 +996,8 @@ func parseCipherInterface(data interface{}, pnConf *Config, module crypto.Crypto
var intf interface{}
decrypted, errDecryption := decryptString(module, data.(string))
if errDecryption != nil {
pnConf.Log.Println(errDecryption, intf)
pnConf.Log.Println(errDecryption, intf, "\nMessage might be not encrypted, returning as is...")

intf = data
return intf, errDecryption
}
Expand Down
Loading

0 comments on commit f5c19c1

Please sign in to comment.