Skip to content

Commit

Permalink
feat: Save code for EncryptionError [WPB-1795] (#2989)
Browse files Browse the repository at this point in the history
* feat: Save code for EncryptionError

* Fixed tests

* Improved some vals naming

* Review fixes

* Code style fix
  • Loading branch information
borichellow authored Sep 11, 2024
1 parent 5fa0b4f commit 2b6e0ac
Show file tree
Hide file tree
Showing 27 changed files with 238 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ class ProteusClientCryptoBoxImpl constructor(
try {
return b()
} catch (e: CryptoException) {
throw ProteusException(e.message, fromCryptoException(e), e.cause)
throw ProteusException(e.message, fromCryptoException(e), e.code.ordinal, e.cause)
} catch (e: Exception) {
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e.cause)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ class ProteusClientCoreCryptoImpl private constructor(private val coreCrypto: Co
return b()
} catch (e: CryptoException) {
// TODO underlying proteus error is not exposed atm
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, null)
} catch (e: Exception) {
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, null)
}
}

Expand Down Expand Up @@ -190,9 +190,9 @@ class ProteusClientCoreCryptoImpl private constructor(private val coreCrypto: Co
coreCrypto.proteusInit()
return ProteusClientCoreCryptoImpl(coreCrypto)
} catch (e: CryptoException) {
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e.cause)
} catch (e: Exception) {
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e.cause)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,15 @@ class ProteusClientCoreCryptoImpl private constructor(
try {
return b()
} catch (e: CoreCryptoException) {
throw ProteusException(e.message, ProteusException.fromProteusCode(coreCrypto.proteusLastErrorCode().toInt()), e)
val proteusLastErrorCode = coreCrypto.proteusLastErrorCode()
throw ProteusException(
e.message,
ProteusException.fromProteusCode(proteusLastErrorCode.toInt()),
proteusLastErrorCode.toInt(),
e
)
} catch (e: Exception) {
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e)
}
}

Expand Down Expand Up @@ -188,9 +194,14 @@ class ProteusClientCoreCryptoImpl private constructor(
coreCrypto.proteusInit()
return ProteusClientCoreCryptoImpl(coreCrypto)
} catch (e: CoreCryptoException) {
throw ProteusException(e.message, ProteusException.fromProteusCode(coreCrypto.proteusLastErrorCode().toInt()), e.cause)
throw ProteusException(
e.message,
ProteusException.fromProteusCode(coreCrypto.proteusLastErrorCode().toInt()),
coreCrypto.proteusLastErrorCode().toInt(),
e.cause
)
} catch (e: Exception) {
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e.cause)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@

package com.wire.kalium.cryptography.exceptions

class ProteusException(message: String?, val code: Code, cause: Throwable? = null) : Exception(message, cause) {
class ProteusException(message: String?, val code: Code, val intCode: Int?, cause: Throwable? = null) : Exception(message, cause) {

constructor(message: String?, code: Int, cause: Throwable? = null) : this(message, fromNativeCode(code), cause)
constructor(message: String?, code: Int, cause: Throwable? = null) : this(
message,
fromNativeCode(code),
code,
cause
)

enum class Code {
/**
Expand Down Expand Up @@ -149,6 +154,9 @@ class ProteusException(message: String?, val code: Code, cause: Throwable? = nul
}

companion object {

const val SESSION_NOT_FOUND_INT = 2

@Suppress("MagicNumber")
fun fromNativeCode(code: Int): Code {
return when (code) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class ProteusClientCryptoBoxImpl : ProteusClient {
if (preKey != null) {
return toPreKey(box.getIdentity().public_key, preKey)
} else {
throw ProteusException("Local identity doesn't exist", ProteusException.Code.UNKNOWN_ERROR)
throw ProteusException("Local identity doesn't exist", ProteusException.Code.UNKNOWN_ERROR, null, null)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class ProteusClientCryptoBoxImpl constructor(
override suspend fun encrypt(message: ByteArray, sessionId: CryptoSessionId): ByteArray {
return wrapException {
box.encryptFromSession(sessionId.value, message)
}?.let { it } ?: throw ProteusException(null, ProteusException.Code.SESSION_NOT_FOUND)
} ?: throw ProteusException(null, ProteusException.Code.SESSION_NOT_FOUND, ProteusException.SESSION_NOT_FOUND_INT)
}

override suspend fun encryptBatched(message: ByteArray, sessionIds: List<CryptoSessionId>): Map<CryptoSessionId, ByteArray> {
Expand Down Expand Up @@ -127,7 +127,7 @@ class ProteusClientCryptoBoxImpl constructor(
} catch (e: CryptoException) {
throw ProteusException(e.message, e.code.ordinal, e.cause)
} catch (e: Exception) {
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause)
throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e.cause)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ sealed interface Message {
is MessageContent.FailedDecryption -> {
mutableMapOf(
typeKey to "failedDecryption",
"code" to "${content.errorCode}",
"size" to "${content.encodedData?.size}",
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ sealed interface MessageContent {

data class FailedDecryption(
val encodedData: ByteArray? = null,
val errorCode: Int? = null,
val isDecryptionResolved: Boolean,
val senderUserId: UserId,
val clientId: ClientId? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ internal inline fun <T : Any> wrapProteusRequest(proteusRequest: () -> T): Eithe
|"cause": ${e.cause} }" """.trimMargin()
)
kaliumLogger.e(e.stackTraceToString())
Either.Left(ProteusFailure(ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause)))
Either.Left(ProteusFailure(ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, null, e.cause)))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ class MessageMapperImpl(
// We store the encoded data in case we decide to try to decrypt them again in the future
is MessageContent.FailedDecryption -> MessageEntityContent.FailedDecryption(
regularMessage.encodedData,
regularMessage.errorCode,
regularMessage.isDecryptionResolved,
regularMessage.senderUserId.toDao(),
regularMessage.clientId?.value
Expand Down Expand Up @@ -611,6 +612,7 @@ fun MessageEntityContent.Regular.toMessageContent(hidden: Boolean, selfUserId: U
is MessageEntityContent.Unknown -> MessageContent.Unknown(this.typeName, this.encodedData, hidden)
is MessageEntityContent.FailedDecryption -> MessageContent.FailedDecryption(
this.encodedData,
this.code,
this.isDecryptionResolved,
this.senderUserId.toModel(),
ClientId(this.senderClientId.orEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ internal class NewMessageEventHandlerImpl(

logger.e("Failed to decrypt event: ${logMap.toJsonElement()}")

val errorCode = if (it is ProteusFailure) it.proteusException.intCode else null

applicationMessageHandler.handleDecryptionError(
eventId = event.id,
conversationId = event.conversationId,
Expand All @@ -82,6 +84,7 @@ internal class NewMessageEventHandlerImpl(
senderClientId = event.senderClientId,
content = MessageContent.FailedDecryption(
encodedData = event.encryptedExternalContent?.data,
errorCode = errorCode,
isDecryptionResolved = false,
senderUserId = event.senderUserId,
clientId = ClientId(event.senderClientId.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ internal class ProteusMessageUnpackerImpl(

is ProteusFailure -> {
val loggableException =
"{ \"code\": \"${it.proteusException.code.name}\", \"message\": \"${it.proteusException.message}\", " +
"{ \"code\": \"${it.proteusException.code.name}\", \"intCode\": \"${it.proteusException.intCode}\"," +
" \"message\": \"${it.proteusException.message}\", " +
"\"error\": \"${it.proteusException.stackTraceToString()}\"," +
"\"senderClientId\": \"${event.senderClientId.value.obfuscateId()}\"," +
"\"senderUserId\": \"${event.senderUserId.value.obfuscateId()}\"," +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class WrapProteusRequestTest {

@Test
fun whenApiRequestReturnNoInternetConnection_thenCorrectErrorIsPropagated() {
val expected = ProteusException(null, ProteusException.Code.PANIC, RuntimeException())
val expected = ProteusException(null, ProteusException.Code.PANIC, 15, RuntimeException())
val actual = wrapProteusRequest { throw expected }

assertIs<Either.Left<ProteusFailure>>(actual)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class PreKeyRepositoryTest {

@Test
fun givenCreatingSessionsThrows_whenPreparingSessions_thenItShouldFail() = runTest {
val exception = ProteusException("PANIC!!!11!eleven!", ProteusException.Code.PANIC)
val exception = ProteusException("PANIC!!!11!eleven!", ProteusException.Code.PANIC, 15)

val preKey = PreKeyDTO(42, "encodedData")
val userPreKeysResult =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class ClientFingerprintUseCaseTest {

@Test
fun givenProteusException_whenGettingRemoteFingerPrint_thenErrorIsReturned() = runTest {
val error = ProteusException(null, ProteusException.Code.DECODE_ERROR)
val error = ProteusException(null, ProteusException.Code.DECODE_ERROR, 3)

val userId = TestUser.USER_ID
val clientId = TestClient.CLIENT_ID
Expand Down Expand Up @@ -147,7 +147,7 @@ class ClientFingerprintUseCaseTest {
.invokes { _ ->
if (getSessionCalled == 0) {
getSessionCalled++
throw ProteusException(null, ProteusException.Code.SESSION_NOT_FOUND)
throw ProteusException(null, ProteusException.Code.SESSION_NOT_FOUND, 2)
}
secondTimeResult
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ class MessageEnvelopeCreatorTest {

@Test
fun givenProteusThrowsDuringEncryption_whenCreatingEnvelope_thenTheFailureShouldBePropagated() = runTest {
val exception = ProteusException("OOPS", ProteusException.Code.PANIC)
val exception = ProteusException("OOPS", ProteusException.Code.PANIC, 15)
coEvery {
proteusClient.encryptBatched(any(), any())
}.throws(exception)
Expand Down Expand Up @@ -368,7 +368,7 @@ class MessageEnvelopeCreatorTest {
fun givenProteusThrowsDuringEncryption_whenCreatingEnvelope_thenNoMoreEncryptionsShouldBeAttempted() = runTest {
coEvery {
proteusClient.encryptBatched(any(), any())
}.throws(ProteusException("OOPS", ProteusException.Code.PANIC))
}.throws(ProteusException("OOPS", ProteusException.Code.PANIC, 15))

every {

Expand Down Expand Up @@ -590,7 +590,7 @@ class MessageEnvelopeCreatorTest {

@Test
fun givenProteusThrowsDuringEncryption_whenCreatingBroadcastEnvelope_thenTheFailureShouldBePropagated() = runTest {
val exception = ProteusException("OOPS", ProteusException.Code.PANIC)
val exception = ProteusException("OOPS", ProteusException.Code.PANIC, 15)
coEvery {
proteusClient.encryptBatched(any(), any())
}.throws(exception)
Expand All @@ -610,7 +610,7 @@ class MessageEnvelopeCreatorTest {
fun givenProteusThrowsDuringEncryption_whenCreatingBroadcastEnvelope_thenNoMoreEncryptionsShouldBeAttempted() = runTest {
coEvery {
proteusClient.encryptBatched(any(), any())
}.throws(ProteusException("OOPS", ProteusException.Code.PANIC))
}.throws(ProteusException("OOPS", ProteusException.Code.PANIC, 15))

every {
protoContentMapper.encodeToProtobuf(any())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class SessionEstablisherTest {

@Test
fun givenProteusClientThrowsWhenCheckingSession_whenPreparingSessions_thenItShouldFail() = runTest {
val exception = ProteusException("PANIC!!!11!eleven!", ProteusException.Code.PANIC)
val exception = ProteusException("PANIC!!!11!eleven!", ProteusException.Code.PANIC, 15)

val (_, sessionEstablisher) = Arrangement()
.withDoesSessionExistThrows(exception)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ class NewMessageEventHandlerTest {
ProteusFailure(
ProteusException(
message = null,
code = ProteusException.Code.DUPLICATE_MESSAGE
code = ProteusException.Code.DUPLICATE_MESSAGE,
intCode = 7
)
)
)
Expand Down Expand Up @@ -104,7 +105,8 @@ class NewMessageEventHandlerTest {
ProteusFailure(
ProteusException(
message = null,
code = ProteusException.Code.INVALID_SIGNATURE
code = ProteusException.Code.INVALID_SIGNATURE,
intCode = 5
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ INSERT INTO MessageFailedToDecryptContent
SELECT local_db.MessageFailedToDecryptContent.message_id,
local_db.MessageFailedToDecryptContent.conversation_id,
local_db.MessageFailedToDecryptContent.unknown_encoded_data,
local_db.MessageFailedToDecryptContent.is_decryption_resolved
local_db.MessageFailedToDecryptContent.is_decryption_resolved,
local_db.MessageFailedToDecryptContent.error_code
FROM local_db.MessageFailedToDecryptContent
LEFT JOIN selfdelete_message_id
ON local_db.MessageFailedToDecryptContent.message_id = selfdelete_message_id.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ RestrictedAssetContent.asset_mime_type AS restrictedAssetMimeType,
RestrictedAssetContent.asset_size AS restrictedAssetSize,
RestrictedAssetContent.asset_name AS restrictedAssetName,
FailedToDecryptContent.unknown_encoded_data AS failedToDecryptData,
FailedToDecryptContent.error_code AS decryptionErrorCode,
FailedToDecryptContent.is_decryption_resolved AS isDecryptionResolved,
ConversationNameChangedContent.conversation_name AS conversationName,
'{' || IFNULL(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ CREATE TABLE MessageFailedToDecryptContent (

unknown_encoded_data BLOB,
is_decryption_resolved INTEGER AS Boolean NOT NULL DEFAULT(0),
error_code INTEGER,

FOREIGN KEY (message_id, conversation_id) REFERENCES Message(id, conversation_id) ON DELETE CASCADE ON UPDATE CASCADE,
PRIMARY KEY (message_id, conversation_id)
Expand Down Expand Up @@ -410,8 +411,8 @@ INSERT OR IGNORE INTO MessageUnknownContent(message_id, conversation_id, unknown
VALUES(?, ?, ?, ?);

insertFailedDecryptionMessageContent:
INSERT OR IGNORE INTO MessageFailedToDecryptContent(message_id, conversation_id, unknown_encoded_data)
VALUES(?, ?, ?);
INSERT OR IGNORE INTO MessageFailedToDecryptContent(message_id, conversation_id, unknown_encoded_data, error_code)
VALUES(?, ?, ?, ?);

insertMissedCallMessage:
INSERT OR IGNORE INTO MessageMissedCallContent(message_id, conversation_id, caller_id)
Expand Down
Loading

0 comments on commit 2b6e0ac

Please sign in to comment.