Fix missing signature validation

This commit is contained in:
nielsandriesse 2021-05-12 15:28:14 +10:00
parent c8cf5ebfa0
commit 174bccb0b7
2 changed files with 50 additions and 53 deletions

View File

@ -8,8 +8,8 @@ class MessagingModuleConfiguration(
val context: Context, val context: Context,
val storage: StorageProtocol, val storage: StorageProtocol,
val messageDataProvider: MessageDataProvider, val messageDataProvider: MessageDataProvider,
val sessionProtocol: SessionProtocol) val sessionProtocol: SessionProtocol
{ ) {
companion object { companion object {
lateinit var shared: MessagingModuleConfiguration lateinit var shared: MessagingModuleConfiguration

View File

@ -65,19 +65,19 @@ object OpenGroupAPIV2 {
} }
data class Request( data class Request(
val verb: HTTP.Verb, val verb: HTTP.Verb,
val room: String?, val room: String?,
val server: String, val server: String,
val endpoint: String, val endpoint: String,
val queryParameters: Map<String, String> = mapOf(), val queryParameters: Map<String, String> = mapOf(),
val parameters: Any? = null, val parameters: Any? = null,
val headers: Map<String, String> = mapOf(), val headers: Map<String, String> = mapOf(),
val isAuthRequired: Boolean = true, val isAuthRequired: Boolean = true,
/** /**
* Always `true` under normal circumstances. You might want to disable * Always `true` under normal circumstances. You might want to disable
* this when running over Lokinet. * this when running over Lokinet.
*/ */
val useOnionRouting: Boolean = true val useOnionRouting: Boolean = true
) )
private fun createBody(parameters: Any?): RequestBody? { private fun createBody(parameters: Any?): RequestBody? {
@ -241,36 +241,42 @@ object OpenGroupAPIV2 {
queryParameters += "from_server_id" to lastId.toString() queryParameters += "from_server_id" to lastId.toString()
} }
val request = Request(verb = GET, room = room, server = server, endpoint = "messages", queryParameters = queryParameters) val request = Request(verb = GET, room = room, server = server, endpoint = "messages", queryParameters = queryParameters)
return send(request).map { jsonList -> return send(request).map { json ->
@Suppress("UNCHECKED_CAST") val rawMessages = jsonList["messages"] as? List<Map<String, Any>> @Suppress("UNCHECKED_CAST") val rawMessages = json["messages"] as? List<Map<String, Any>>
?: throw Error.ParsingFailed ?: throw Error.ParsingFailed
val lastMessageServerID = storage.getLastMessageServerId(room, server) ?: 0 parseMessages(room, server, rawMessages)
var currentLastMessageServerID = lastMessageServerID
val messages = rawMessages.mapNotNull { json ->
try {
val message = OpenGroupMessageV2.fromJSON(json) ?: return@mapNotNull null
if (message.serverID == null || message.sender.isNullOrEmpty()) return@mapNotNull null
val sender = message.sender
val data = decode(message.base64EncodedData)
val signature = decode(message.base64EncodedSignature)
val publicKey = Hex.fromStringCondensed(sender.removing05PrefixIfNeeded())
val isValid = curve.verifySignature(publicKey, data, signature)
if (!isValid) {
Log.d("Loki", "Ignoring message with invalid signature")
return@mapNotNull null
}
if (message.serverID > lastMessageServerID) {
currentLastMessageServerID = message.serverID
}
message
} catch (e: Exception) {
null
}
}
storage.setLastMessageServerId(room, server, currentLastMessageServerID)
messages
} }
} }
private fun parseMessages(room: String, server: String, rawMessages: List<Map<*, *>>): List<OpenGroupMessageV2> {
val storage = MessagingModuleConfiguration.shared.storage
val lastMessageServerID = storage.getLastMessageServerId(room, server) ?: 0
var currentLastMessageServerID = lastMessageServerID
val messages = rawMessages.mapNotNull { json ->
json as Map<String, Any>
try {
val message = OpenGroupMessageV2.fromJSON(json) ?: return@mapNotNull null
if (message.serverID == null || message.sender.isNullOrEmpty()) return@mapNotNull null
val sender = message.sender
val data = decode(message.base64EncodedData)
val signature = decode(message.base64EncodedSignature)
val publicKey = Hex.fromStringCondensed(sender.removing05PrefixIfNeeded())
val isValid = curve.verifySignature(publicKey, data, signature)
if (!isValid) {
Log.d("Loki", "Ignoring message with invalid signature.")
return@mapNotNull null
}
if (message.serverID > lastMessageServerID) {
currentLastMessageServerID = message.serverID
}
message
} catch (e: Exception) {
null
}
}
storage.setLastMessageServerId(room, server, currentLastMessageServerID)
return messages
}
// endregion // endregion
// region Message Deletion // region Message Deletion
@ -381,22 +387,13 @@ object OpenGroupAPIV2 {
val idsAsString = JsonUtil.toJson(json["deletions"]) val idsAsString = JsonUtil.toJson(json["deletions"])
val deletedServerIDs = JsonUtil.fromJson<List<MessageDeletion>>(idsAsString, type) ?: throw Error.ParsingFailed val deletedServerIDs = JsonUtil.fromJson<List<MessageDeletion>>(idsAsString, type) ?: throw Error.ParsingFailed
val lastDeletionServerID = storage.getLastDeletionServerId(roomID, server) ?: 0 val lastDeletionServerID = storage.getLastDeletionServerId(roomID, server) ?: 0
val serverID = deletedServerIDs.maxByOrNull {it.id } ?: MessageDeletion.EMPTY val serverID = deletedServerIDs.maxByOrNull { it.id } ?: MessageDeletion.EMPTY
if (serverID.id > lastDeletionServerID) { if (serverID.id > lastDeletionServerID) {
storage.setLastDeletionServerId(roomID, server, serverID.id) storage.setLastDeletionServerId(roomID, server, serverID.id)
} }
// Messages // Messages
val rawMessages = json["messages"] as? List<Map<String, Any>> ?: return@mapNotNull null val rawMessages = json["messages"] as? List<Map<String, Any>> ?: return@mapNotNull null
val lastMessageServerID = storage.getLastMessageServerId(roomID, server) ?: 0 val messages = parseMessages(roomID, server, rawMessages)
var currentLastMessageServerID = lastMessageServerID
val messages = rawMessages.mapNotNull { rawMessage ->
val message = OpenGroupMessageV2.fromJSON(rawMessage)?.apply {
currentLastMessageServerID = maxOf(currentLastMessageServerID,this.serverID ?: 0)
}
// TODO: We need to check the signature here...
message
}
storage.setLastMessageServerId(roomID, server, currentLastMessageServerID)
roomID to CompactPollResult( roomID to CompactPollResult(
messages = messages, messages = messages,
deletions = deletedServerIDs.map { it.deletedMessageId }, deletions = deletedServerIDs.map { it.deletedMessageId },