84 lines
3.4 KiB
Kotlin
84 lines
3.4 KiB
Kotlin
package org.session.libsession.messaging.utilities
|
|
|
|
import com.google.protobuf.ByteString
|
|
import org.session.libsignal.utilities.logging.Log
|
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.Envelope
|
|
import org.session.libsignal.service.internal.websocket.WebSocketProtos.WebSocketMessage
|
|
import org.session.libsignal.service.internal.websocket.WebSocketProtos.WebSocketRequestMessage
|
|
import java.security.SecureRandom
|
|
|
|
object MessageWrapper {
|
|
|
|
// region Types
|
|
sealed class Error(val description: String) : Exception(description) {
|
|
object FailedToWrapData : Error("Failed to wrap data.")
|
|
object FailedToWrapMessageInEnvelope : Error("Failed to wrap message in envelope.")
|
|
object FailedToWrapEnvelopeInWebSocketMessage : Error("Failed to wrap envelope in web socket message.")
|
|
object FailedToUnwrapData : Error("Failed to unwrap data.")
|
|
}
|
|
// endregion
|
|
|
|
// region Wrapping
|
|
/**
|
|
* Wraps `message` in a `SignalServiceProtos.Envelope` and then a `WebSocketProtos.WebSocketMessage` to match the desktop application.
|
|
*/
|
|
fun wrap(type: Envelope.Type, timestamp: Long, senderPublicKey: String, content: ByteArray): ByteArray {
|
|
try {
|
|
val envelope = createEnvelope(type, timestamp, senderPublicKey, content)
|
|
val webSocketMessage = createWebSocketMessage(envelope)
|
|
return webSocketMessage.toByteArray()
|
|
} catch (e: Exception) {
|
|
throw if (e is Error) { e } else { Error.FailedToWrapData }
|
|
}
|
|
}
|
|
|
|
private fun createEnvelope(type: Envelope.Type, timestamp: Long, senderPublicKey: String, content: ByteArray): Envelope {
|
|
try {
|
|
val builder = Envelope.newBuilder()
|
|
builder.type = type
|
|
builder.timestamp = timestamp
|
|
builder.source = senderPublicKey
|
|
builder.sourceDevice = 1
|
|
builder.content = ByteString.copyFrom(content)
|
|
return builder.build()
|
|
} catch (e: Exception) {
|
|
Log.d("Loki", "Failed to wrap message in envelope: ${e.message}.")
|
|
throw Error.FailedToWrapMessageInEnvelope
|
|
}
|
|
}
|
|
|
|
private fun createWebSocketMessage(envelope: Envelope): WebSocketMessage {
|
|
try {
|
|
val requestBuilder = WebSocketRequestMessage.newBuilder()
|
|
requestBuilder.verb = "PUT"
|
|
requestBuilder.path = "/api/v1/message"
|
|
requestBuilder.id = SecureRandom.getInstance("SHA1PRNG").nextLong()
|
|
requestBuilder.body = envelope.toByteString()
|
|
val messageBuilder = WebSocketMessage.newBuilder()
|
|
messageBuilder.request = requestBuilder.build()
|
|
messageBuilder.type = WebSocketMessage.Type.REQUEST
|
|
return messageBuilder.build()
|
|
} catch (e: Exception) {
|
|
Log.d("Loki", "Failed to wrap envelope in web socket message: ${e.message}.")
|
|
throw Error.FailedToWrapEnvelopeInWebSocketMessage
|
|
}
|
|
}
|
|
// endregion
|
|
|
|
// region Unwrapping
|
|
/**
|
|
* `data` shouldn't be base 64 encoded.
|
|
*/
|
|
fun unwrap(data: ByteArray): ByteArray {
|
|
try {
|
|
val webSocketMessage = WebSocketMessage.parseFrom(data)
|
|
val envelopeAsData = webSocketMessage.request.body
|
|
return envelopeAsData.toByteArray()
|
|
} catch (e: Exception) {
|
|
Log.d("Loki", "Failed to unwrap data: ${e.message}.")
|
|
throw Error.FailedToUnwrapData
|
|
}
|
|
}
|
|
// endregion
|
|
}
|