Skip to content

Commit

Permalink
Can read unencrypted history message when crypto is configured. (#153)
Browse files Browse the repository at this point in the history
Co-authored-by: PubNub Release Bot <[email protected]>
Co-authored-by: Serhii Mamontov <[email protected]>
  • Loading branch information
3 people authored Nov 8, 2023
1 parent 191f1d2 commit fad0116
Show file tree
Hide file tree
Showing 15 changed files with 369 additions and 83 deletions.
13 changes: 9 additions & 4 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: kotlin
version: 7.7.1
version: 7.7.2
schema: 1
scm: github.com/pubnub/kotlin
files:
- build/libs/pubnub-kotlin-7.7.1-all.jar
- build/libs/pubnub-kotlin-7.7.2-all.jar
sdks:
-
type: library
Expand All @@ -23,8 +23,8 @@ sdks:
-
distribution-type: library
distribution-repository: maven
package-name: pubnub-kotlin-7.7.1
location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-kotlin/7.7.1/pubnub-kotlin-7.7.1.jar
package-name: pubnub-kotlin-7.7.2
location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-kotlin/7.7.2/pubnub-kotlin-7.7.2.jar
supported-platforms:
supported-operating-systems:
Android:
Expand Down Expand Up @@ -114,6 +114,11 @@ sdks:
license-url: https://www.apache.org/licenses/LICENSE-2.0.txt
is-required: Required
changelog:
- date: 2023-11-08
version: v7.7.2
changes:
- type: bug
text: "Fixed reading unencrypted history message when crypto is configured."
- date: 2023-10-30
version: v7.7.1
changes:
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## v7.7.2
November 08 2023

#### Fixed
- Fixed reading unencrypted history message when crypto is configured.



## v7.7.1
October 30 2023

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ You will need the publish and subscribe keys to authenticate your app. Get your
<dependency>
<groupId>com.pubnub</groupId>
<artifactId>pubnub-kotlin</artifactId>
<version>7.7.1</version>
<version>7.7.2</version>
</dependency>
```

* for Gradle, add the following dependency in your `gradle.build`:
```groovy
implementation 'com.pubnub:pubnub-kotlin:7.7.1'
implementation 'com.pubnub:pubnub-kotlin:7.7.2'
```

2. Configure your keys:
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ SONATYPE_HOST=DEFAULT
SONATYPE_AUTOMATIC_RELEASE=true
GROUP=com.pubnub
POM_ARTIFACT_ID=pubnub-kotlin
VERSION_NAME=7.7.1
VERSION_NAME=7.7.2
POM_PACKAGING=jar

POM_NAME=PubNub Kotlin SDK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import com.google.gson.JsonPrimitive
import com.pubnub.api.CommonUtils
import com.pubnub.api.CommonUtils.emoji
import com.pubnub.api.CommonUtils.randomChannel
import com.pubnub.api.PubNub
import com.pubnub.api.PubNubError
import com.pubnub.api.crypto.CryptoModule
import com.pubnub.api.models.consumer.history.Action
import com.pubnub.api.models.consumer.history.HistoryMessageType
import com.pubnub.api.models.consumer.history.PNFetchMessageItem
Expand Down Expand Up @@ -61,6 +64,56 @@ class HistoryIntegrationTest : BaseIntegrationTest() {
assertEquals(expectedHistoryResultChannels, historyResult?.messages)
}

@Test
fun `when reading unencrypted message from history using pubNub with configured encryption should log error and return error in response and return unencrypted message`() {
val pnConfigurationWithCrypto = getBasicPnConfiguration()
val cipherKey = "enigma"
pnConfigurationWithCrypto.cryptoModule =
CryptoModule.createAesCbcCryptoModule(cipherKey = cipherKey, randomIv = false)
val pubNubWithCrypto = PubNub(pnConfigurationWithCrypto)

val channel = randomChannel()
val expectedMeta = JsonObject().also { it.add("thisIsMeta", JsonPrimitive("thisIsMetaValue")) }
val expectedMessage = "this is not encrypted message"

val result = pubnub.publish(
channel = channel,
message = expectedMessage,
meta = expectedMeta,
shouldStore = true,
ttl = 60
).sync()!!

var historyResult: PNHistoryResult? = null

await
.pollInterval(Duration.ofMillis(1_000))
.pollDelay(Duration.ofMillis(1_000))
.atMost(Duration.ofMillis(10_000))
.untilAsserted {
historyResult = pubNubWithCrypto.history(
channel = channel,
includeMeta = true,
includeTimetoken = true,
).sync()

assertNotNull(historyResult)
assertThat(historyResult?.messages, hasSize(not(0)))
}

val expectedHistoryResultChannels =
listOf(
PNHistoryItemResult(
entry = JsonPrimitive(expectedMessage),
timetoken = result.timetoken,
meta = expectedMeta,
error = PubNubError.CRYPTO_IS_CONFIGURED_BUT_MESSAGE_IS_NOT_ENCRYPTED
)
)

assertEquals(expectedHistoryResultChannels, historyResult?.messages)
}

@Test
fun fetchMessagesSingleScenario() {
val channel = randomChannel()
Expand Down Expand Up @@ -150,6 +203,65 @@ class HistoryIntegrationTest : BaseIntegrationTest() {
)
}

@Test
fun `when fetching unencrypted message using pubNub with configured encryption should log error and return error in respone and return unencrypted message`() {
val pnConfigurationWithCrypto = getBasicPnConfiguration()
val cipherKey = "enigma"
pnConfigurationWithCrypto.cryptoModule =
CryptoModule.createLegacyCryptoModule(cipherKey = cipherKey, randomIv = true)
val pubNubWithCrypto = PubNub(pnConfigurationWithCrypto)

val channel = randomChannel()
val expectedMeta = JsonObject().also { it.add("thisIsMeta", JsonPrimitive("thisIsMetaValue")) }
val expectedMessage = CommonUtils.generatePayload()

val result = pubnub.publish(
channel = channel,
message = expectedMessage,
meta = expectedMeta,
shouldStore = true,
ttl = 60
).sync()!!

var fetchResult: PNFetchMessagesResult? = null

await
.pollInterval(Duration.ofMillis(1_000))
.pollDelay(Duration.ofMillis(1_000))
.atMost(Duration.ofMillis(10_000))
.untilAsserted {
fetchResult = pubNubWithCrypto.fetchMessages(
includeMeta = true,
includeMessageActions = true,
includeMessageType = true,
includeUUID = true,
channels = listOf(channel)
).sync()
assertNotNull(fetchResult)
assertThat(fetchResult?.channels, aMapWithSize(not(0)))
}

val expectedItem = PNFetchMessageItem(
uuid = pubnub.configuration.userId.value,
message = expectedMessage,
timetoken = result.timetoken,
meta = expectedMeta,
messageType = HistoryMessageType.Message,
actions = emptyMap<String, Map<String, List<Action>>>(),
error = PubNubError.CRYPTO_IS_CONFIGURED_BUT_MESSAGE_IS_NOT_ENCRYPTED
)

val expectedChannelsResponse: Map<String, List<PNFetchMessageItem>> =
mapOf(
channel to listOf(
expectedItem
)
)

val fetchMessageItem = fetchResult!!
assertEquals(expectedChannelsResponse, fetchMessageItem.channels)
}

@Test
fun always() {
assertEquals(
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/pubnub/api/PubNub.kt
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class PubNub internal constructor(

companion object {
private const val TIMESTAMP_DIVIDER = 1000
private const val SDK_VERSION = "7.7.1"
private const val SDK_VERSION = "7.7.2"
private const val MAX_SEQUENCE = 65535

/**
Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/com/pubnub/api/PubNubError.kt
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ enum class PubNubError(private val code: Int, val message: String) {
"Encryption of empty data not allowed."
),

CRYPTO_IS_CONFIGURED_BUT_MESSAGE_IS_NOT_ENCRYPTED(
177,
"Crypto is configured but message is not encrypted."
),

;

override fun toString(): String {
Expand Down
6 changes: 5 additions & 1 deletion src/main/kotlin/com/pubnub/api/endpoints/FetchMessages.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ class FetchMessages internal constructor(
val body = input.body()!!
val channelsMap = body.channels.mapValues { (_, value) ->
value.map { serverMessageItem ->
val newMessage = serverMessageItem.message.processHistoryMessage(pubnub.cryptoModule, pubnub.mapper)
val (newMessage, error) = serverMessageItem.message.processHistoryMessage(
pubnub.cryptoModule,
pubnub.mapper
)
val newActions =
if (includeMessageActions) serverMessageItem.actions ?: mapOf() else serverMessageItem.actions
PNFetchMessageItem(
Expand All @@ -92,6 +95,7 @@ class FetchMessages internal constructor(
timetoken = serverMessageItem.timetoken,
actions = newActions,
messageType = if (includeMessageType) HistoryMessageType.of(serverMessageItem.messageType) else null,
error = error
)
}
}.toMap()
Expand Down
12 changes: 8 additions & 4 deletions src/main/kotlin/com/pubnub/api/endpoints/History.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,26 +71,30 @@ class History internal constructor(

val historyEntry = iterator.next()

var message: JsonElement
var timetoken: Long? = null
var meta: JsonElement? = null
val historyMessageWithError: Pair<JsonElement, PubNubError?>

if (includeTimetoken || includeMeta) {
message = pubnub.mapper.getField(historyEntry, "message")!!.processHistoryMessage(pubnub.cryptoModule, pubnub.mapper)
historyMessageWithError = pubnub.mapper.getField(historyEntry, "message")!!.processHistoryMessage(pubnub.cryptoModule, pubnub.mapper)
if (includeTimetoken) {
timetoken = pubnub.mapper.elementToLong(historyEntry, "timetoken")
}
if (includeMeta) {
meta = pubnub.mapper.getField(historyEntry, "meta")
}
} else {
message = historyEntry.processHistoryMessage(pubnub.cryptoModule, pubnub.mapper)
historyMessageWithError = historyEntry.processHistoryMessage(pubnub.cryptoModule, pubnub.mapper)
}

val message: JsonElement = historyMessageWithError.first
val error: PubNubError? = historyMessageWithError.second

val historyItem = PNHistoryItemResult(
entry = message,
timetoken = timetoken,
meta = meta
meta = meta,
error = error
)

messages.add(historyItem)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.pubnub.api.models.consumer.history

import com.google.gson.JsonElement
import com.pubnub.api.PubNub
import com.pubnub.api.PubNubError
import com.pubnub.api.endpoints.FetchMessages
import com.pubnub.api.models.consumer.PNBoundedPage

Expand All @@ -28,17 +29,20 @@ data class PNFetchMessagesResult(
* The key of the map is the action type. The value is another map,
* which key is the actual value of the message action,
* and the key being a list of actions, ie. a list of UUIDs which have posted such a message action.
* @property messageType The message type associated with the item.
*
* @see [Action]
* @property messageType The message type associated with the item.
* @property error The error associated with message retrieval, if any.
* e.g. a message is unencrypted but PubNub instance is configured with the Crypto
* so PubNub can't decrypt the unencrypted message and return the message.
*/
data class PNFetchMessageItem(
val uuid: String?,
val message: JsonElement,
val meta: JsonElement?,
val timetoken: Long,
val actions: Map<String, Map<String, List<Action>>>? = null,
val messageType: HistoryMessageType?
val messageType: HistoryMessageType?,
val error: PubNubError? = null
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.pubnub.api.models.consumer.history

import com.google.gson.JsonElement
import com.pubnub.api.PubNub
import com.pubnub.api.PubNubError
import com.pubnub.api.endpoints.History

/**
Expand All @@ -24,9 +25,13 @@ class PNHistoryResult internal constructor(
* @property timetoken Publish timetoken of the message, if requested via [History.includeTimetoken]
* @property meta Metadata of the message, if requested via [History.includeMeta].
* Is `null` if not requested, otherwise an empty string if requested but no associated metadata.
* @property error The error associated with message retrieval, if any.
* e.g. a message is unencrypted but PubNub instance is configured with the Crypto
* so PubNub can't decrypt the unencrypted message and return the message.
*/
data class PNHistoryItemResult(
val entry: JsonElement,
val timetoken: Long? = null,
val meta: JsonElement? = null
val meta: JsonElement? = null,
val error: PubNubError? = null
)
Loading

0 comments on commit fad0116

Please sign in to comment.