diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt deleted file mode 100644 index 362336196a..0000000000 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt +++ /dev/null @@ -1,188 +0,0 @@ -package org.thoughtcrime.securesms.messages - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.mockk.every -import io.mockk.mockkObject -import io.mockk.mockkStatic -import io.mockk.unmockkStatic -import okio.ByteString -import org.junit.After -import org.junit.Before -import org.junit.Ignore -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.signal.core.util.logging.Log -import org.signal.libsignal.protocol.ecc.ECKeyPair -import org.signal.libsignal.zkgroup.profiles.ProfileKey -import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil -import org.thoughtcrime.securesms.recipients.Recipient -import org.thoughtcrime.securesms.testing.AliceClient -import org.thoughtcrime.securesms.testing.BobClient -import org.thoughtcrime.securesms.testing.Entry -import org.thoughtcrime.securesms.testing.FakeClientHelpers -import org.thoughtcrime.securesms.testing.SignalActivityRule -import org.thoughtcrime.securesms.testing.awaitFor -import org.whispersystems.signalservice.internal.push.Envelope -import org.whispersystems.signalservice.internal.websocket.WebSocketMessage -import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage -import java.util.regex.Pattern -import kotlin.random.Random -import kotlin.time.Duration.Companion.minutes -import kotlin.time.Duration.Companion.seconds -import android.util.Log as AndroidLog - -/** - * Sends N messages from Bob to Alice to track performance of Alice's processing of messages. - */ -@Ignore("Ignore test in normal testing as it's a performance test with no assertions") -@RunWith(AndroidJUnit4::class) -class MessageProcessingPerformanceTest { - - companion object { - private val TAG = Log.tag(MessageProcessingPerformanceTest::class.java) - private val TIMING_TAG = "TIMING_$TAG".substring(0..23) - - private val DECRYPTION_TIME_PATTERN = Pattern.compile("^Decrypted (?\\d+) envelopes in (?\\d+) ms.*$") - } - - @get:Rule - val harness = SignalActivityRule() - - private val trustRoot: ECKeyPair = ECKeyPair.generate() - - @Before - fun setup() { - mockkStatic(SealedSenderAccessUtil::class) - every { SealedSenderAccessUtil.getCertificateValidator() } returns FakeClientHelpers.noOpCertificateValidator - - mockkObject(MessageContentProcessor) - every { MessageContentProcessor.create(harness.application) } returns TimingMessageContentProcessor(harness.application) - } - - @After - fun after() { - unmockkStatic(SealedSenderAccessUtil::class) - unmockkStatic(MessageContentProcessor::class) - } - - @Test - fun testPerformance() { - val aliceClient = AliceClient( - serviceId = harness.self.requireServiceId(), - e164 = harness.self.requireE164(), - trustRoot = trustRoot - ) - - val bob = Recipient.resolved(harness.others[0]) - val bobClient = BobClient( - serviceId = bob.requireServiceId(), - e164 = bob.requireE164(), - identityKeyPair = harness.othersKeys[0], - trustRoot = trustRoot, - profileKey = ProfileKey(bob.profileKey) - ) - - // Send the initial messages to get past the prekey phase - establishSession(aliceClient, bobClient, bob) - - // Have Bob generate N messages that will be received by Alice - val messageCount = 100 - val envelopes = generateInboundEnvelopes(bobClient, messageCount) - val firstTimestamp = envelopes.first().timestamp - val lastTimestamp = envelopes.last().timestamp ?: 0 - - // Inject the envelopes into the websocket - // TODO: mock websocket messages - - // Wait until they've all been fully decrypted + processed - harness - .inMemoryLogger - .getLockForUntil(TimingMessageContentProcessor.endTagPredicate(lastTimestamp)) - .awaitFor(1.minutes) - - harness.inMemoryLogger.flush() - - // Process logs for timing data - val entries = harness.inMemoryLogger.entries() - - // Calculate decryption average - val totalDecryptDuration: Long = entries - .mapNotNull { entry -> entry.message?.let { DECRYPTION_TIME_PATTERN.matcher(it) } } - .filter { it.matches() } - .drop(1) // Ignore the first message, which represents the prekey exchange - .sumOf { it.group("duration")!!.toLong() } - - AndroidLog.w(TAG, "Decryption: Average runtime: ${totalDecryptDuration.toFloat() / messageCount.toFloat()}ms") - - // Calculate MessageContentProcessor - - val takeLast: List = entries.filter { it.tag == TimingMessageContentProcessor.TAG }.drop(2) - val iterator = takeLast.iterator() - var processCount = 0L - var processDuration = 0L - while (iterator.hasNext()) { - val start = iterator.next() - val end = iterator.next() - processCount++ - processDuration += end.timestamp - start.timestamp - } - - AndroidLog.w(TAG, "MessageContentProcessor.process: Average runtime: ${processDuration.toFloat() / processCount.toFloat()}ms") - - // Calculate messages per second from "retrieving" first message post session initialization to processing last message - - val start = entries.first { it.message == "Retrieved envelope! $firstTimestamp" } - val end = entries.first { it.message == TimingMessageContentProcessor.endTag(lastTimestamp) } - - val duration = (end.timestamp - start.timestamp).toFloat() / 1000f - val messagePerSecond = messageCount.toFloat() / duration - - AndroidLog.w(TAG, "Processing $messageCount messages took ${duration}s or ${messagePerSecond}m/s") - } - - private fun establishSession(aliceClient: AliceClient, bobClient: BobClient, bob: Recipient) { - // Send message from Bob to Alice (self) - val firstPreKeyMessageTimestamp = System.currentTimeMillis() - val encryptedEnvelope = bobClient.encrypt(firstPreKeyMessageTimestamp) - - val aliceProcessFirstMessageLatch = harness - .inMemoryLogger - .getLockForUntil(TimingMessageContentProcessor.endTagPredicate(firstPreKeyMessageTimestamp)) - - Thread { aliceClient.process(encryptedEnvelope, System.currentTimeMillis()) }.start() - aliceProcessFirstMessageLatch.awaitFor(15.seconds) - - // Send message from Alice to Bob - val aliceNow = System.currentTimeMillis() - bobClient.decrypt(aliceClient.encrypt(aliceNow, bob), aliceNow) - } - - private fun generateInboundEnvelopes(bobClient: BobClient, count: Int): List { - val envelopes = ArrayList(count) - var now = System.currentTimeMillis() - for (i in 0..count) { - envelopes += bobClient.encrypt(now) - now += 3 - } - - return envelopes - } - - private fun webSocketTombstone(): ByteString { - return WebSocketMessage(request = WebSocketRequestMessage(verb = "PUT", path = "/api/v1/queue/empty")).encodeByteString() - } - - private fun Envelope.toWebSocketPayload(): ByteString { - return WebSocketMessage( - type = WebSocketMessage.Type.REQUEST, - request = WebSocketRequestMessage( - verb = "PUT", - path = "/api/v1/message", - id = Random(System.currentTimeMillis()).nextLong(), - headers = listOf("X-Signal-Timestamp: ${this.timestamp}"), - body = this.encodeByteString() - ) - ).encodeByteString() - } -} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TimingMessageContentProcessor.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TimingMessageContentProcessor.kt deleted file mode 100644 index 20073a9453..0000000000 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/TimingMessageContentProcessor.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.thoughtcrime.securesms.messages - -import android.content.Context -import org.signal.core.util.logging.Log -import org.thoughtcrime.securesms.testing.LogPredicate -import org.thoughtcrime.securesms.util.SignalLocalMetrics -import org.whispersystems.signalservice.api.crypto.EnvelopeMetadata -import org.whispersystems.signalservice.internal.push.Content -import org.whispersystems.signalservice.internal.push.Envelope - -class TimingMessageContentProcessor(context: Context) : MessageContentProcessor(context) { - companion object { - val TAG = Log.tag(TimingMessageContentProcessor::class.java) - - fun endTagPredicate(timestamp: Long): LogPredicate = { entry -> - entry.tag == TAG && entry.message == endTag(timestamp) - } - - private fun startTag(timestamp: Long) = "$timestamp start" - fun endTag(timestamp: Long) = "$timestamp end" - } - - override fun process(envelope: Envelope, content: Content, metadata: EnvelopeMetadata, serverDeliveredTimestamp: Long, processingEarlyContent: Boolean, localMetric: SignalLocalMetrics.MessageReceive?) { - Log.d(TAG, startTag(envelope.timestamp!!)) - super.process(envelope, content, metadata, serverDeliveredTimestamp, processingEarlyContent, localMetric) - Log.d(TAG, endTag(envelope.timestamp!!)) - } -} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt deleted file mode 100644 index 433816251b..0000000000 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/AliceClient.kt +++ /dev/null @@ -1,58 +0,0 @@ -package org.thoughtcrime.securesms.testing - -import org.signal.core.models.ServiceId -import org.signal.core.util.logging.Log -import org.signal.libsignal.protocol.ecc.ECKeyPair -import org.signal.libsignal.zkgroup.profiles.ProfileKey -import org.thoughtcrime.securesms.dependencies.AppDependencies -import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.messages.protocol.BufferedProtocolStore -import org.thoughtcrime.securesms.recipients.Recipient -import org.thoughtcrime.securesms.testing.FakeClientHelpers.toEnvelope -import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.Envelope - -/** - * Welcome to Alice's Client. - * - * Alice represent the Android instrumentation test user. Unlike [BobClient] much less is needed here - * as it can make use of the standard Signal Android App infrastructure. - */ -class AliceClient(val serviceId: ServiceId, val e164: String, val trustRoot: ECKeyPair) { - - companion object { - val TAG = Log.tag(AliceClient::class.java) - } - - private val aliceSenderCertificate = FakeClientHelpers.createCertificateFor( - trustRoot = trustRoot, - uuid = serviceId.rawUuid, - e164 = e164, - deviceId = 1, - identityKey = SignalStore.account.aciIdentityKey.publicKey.publicKey, - expires = 31337 - ) - - fun process(envelope: Envelope, serverDeliveredTimestamp: Long) { - val start = System.currentTimeMillis() - val bufferedStore = BufferedProtocolStore.create() - AppDependencies.incomingMessageObserver - .processEnvelope(bufferedStore, envelope, serverDeliveredTimestamp) - ?.mapNotNull { it.run() } - ?.forEach { it.enqueue() } - - bufferedStore.flushToDisk() - val end = System.currentTimeMillis() - Log.d(TAG, "${end - start}") - } - - fun encrypt(now: Long, destination: Recipient): Envelope { - return AppDependencies.signalServiceMessageSender.getEncryptedMessage( - SignalServiceAddress(destination.requireServiceId(), destination.requireE164()), - FakeClientHelpers.getSealedSenderAccess(ProfileKey(destination.profileKey), aliceSenderCertificate), - 1, - FakeClientHelpers.encryptedTextMessage(now), - false - ).toEnvelope(now, destination.requireServiceId()) - } -} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt deleted file mode 100644 index 4aa61ba05e..0000000000 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/BobClient.kt +++ /dev/null @@ -1,195 +0,0 @@ -package org.thoughtcrime.securesms.testing - -import org.signal.core.models.ServiceId -import org.signal.core.util.readToSingleInt -import org.signal.core.util.select -import org.signal.libsignal.protocol.IdentityKey -import org.signal.libsignal.protocol.IdentityKeyPair -import org.signal.libsignal.protocol.SessionBuilder -import org.signal.libsignal.protocol.SignalProtocolAddress -import org.signal.libsignal.protocol.ecc.ECKeyPair -import org.signal.libsignal.protocol.ecc.ECPublicKey -import org.signal.libsignal.protocol.groups.state.SenderKeyRecord -import org.signal.libsignal.protocol.state.IdentityKeyStore -import org.signal.libsignal.protocol.state.IdentityKeyStore.IdentityChange -import org.signal.libsignal.protocol.state.KyberPreKeyRecord -import org.signal.libsignal.protocol.state.PreKeyBundle -import org.signal.libsignal.protocol.state.PreKeyRecord -import org.signal.libsignal.protocol.state.SessionRecord -import org.signal.libsignal.protocol.state.SignedPreKeyRecord -import org.signal.libsignal.protocol.util.KeyHelper -import org.signal.libsignal.zkgroup.profiles.ProfileKey -import org.thoughtcrime.securesms.crypto.ProfileKeyUtil -import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil -import org.thoughtcrime.securesms.database.KyberPreKeyTable -import org.thoughtcrime.securesms.database.OneTimePreKeyTable -import org.thoughtcrime.securesms.database.SignalDatabase -import org.thoughtcrime.securesms.database.SignedPreKeyTable -import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.testing.FakeClientHelpers.toEnvelope -import org.whispersystems.signalservice.api.SignalServiceAccountDataStore -import org.whispersystems.signalservice.api.SignalSessionLock -import org.whispersystems.signalservice.api.crypto.SealedSenderAccess -import org.whispersystems.signalservice.api.crypto.SignalServiceCipher -import org.whispersystems.signalservice.api.crypto.SignalSessionBuilder -import org.whispersystems.signalservice.api.push.DistributionId -import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.Envelope -import java.util.UUID -import java.util.concurrent.locks.ReentrantLock - -/** - * Welcome to Bob's Client. - * - * Bob is a "fake" client that can start a session with the Android instrumentation test user (Alice). - * - * Bob can create a new session using a prekey bundle created from Alice's prekeys, send a message, decrypt - * a return message from Alice, and that'll start a standard Signal session with normal keys/ratcheting. - */ -class BobClient(val serviceId: ServiceId, val e164: String, val identityKeyPair: IdentityKeyPair, val trustRoot: ECKeyPair, val profileKey: ProfileKey) { - - private val serviceAddress = SignalServiceAddress(serviceId, e164) - private val registrationId = KeyHelper.generateRegistrationId(false) - private val aciStore = BobSignalServiceAccountDataStore(registrationId, identityKeyPair) - private val senderCertificate = FakeClientHelpers.createCertificateFor(trustRoot, serviceId.rawUuid, e164, 1, identityKeyPair.publicKey.publicKey, 31337) - private val sessionLock = object : SignalSessionLock { - private val lock = ReentrantLock() - - override fun acquire(): SignalSessionLock.Lock { - lock.lock() - return SignalSessionLock.Lock { lock.unlock() } - } - } - - /** Inspired by SignalServiceMessageSender#getEncryptedMessage */ - fun encrypt(now: Long): Envelope { - val envelopeContent = FakeClientHelpers.encryptedTextMessage(now) - - val cipher = SignalServiceCipher(serviceAddress, 1, aciStore, sessionLock, null) - - if (!aciStore.containsSession(getAliceProtocolAddress())) { - val sessionBuilder = SignalSessionBuilder(sessionLock, SessionBuilder(aciStore, getAliceProtocolAddress())) - sessionBuilder.process(getAlicePreKeyBundle()) - } - - return cipher.encrypt(getAliceProtocolAddress(), getAliceUnidentifiedAccess(), envelopeContent) - .toEnvelope(envelopeContent.content.get().dataMessage!!.timestamp!!, getAliceServiceId()) - } - - fun decrypt(envelope: Envelope, serverDeliveredTimestamp: Long) { - val cipher = SignalServiceCipher(serviceAddress, 1, aciStore, sessionLock, SealedSenderAccessUtil.getCertificateValidator()) - cipher.decrypt(envelope, serverDeliveredTimestamp) - } - - private fun getAliceServiceId(): ServiceId { - return SignalStore.account.requireAci() - } - - private fun getAlicePreKeyBundle(): PreKeyBundle { - val selfPreKeyId = SignalDatabase.rawDatabase - .select(OneTimePreKeyTable.KEY_ID) - .from(OneTimePreKeyTable.TABLE_NAME) - .where("${OneTimePreKeyTable.ACCOUNT_ID} = ?", getAliceServiceId().toString()) - .run() - .readToSingleInt(-1) - - val selfPreKeyRecord = SignalDatabase.oneTimePreKeys.get(getAliceServiceId(), selfPreKeyId)!! - - val selfSignedPreKeyId = SignalDatabase.rawDatabase - .select(SignedPreKeyTable.KEY_ID) - .from(SignedPreKeyTable.TABLE_NAME) - .where("${SignedPreKeyTable.ACCOUNT_ID} = ?", getAliceServiceId().toString()) - .run() - .readToSingleInt(-1) - - val selfSignedPreKeyRecord = SignalDatabase.signedPreKeys.get(getAliceServiceId(), selfSignedPreKeyId)!! - - val selfSignedKyberPreKeyId = SignalDatabase.rawDatabase - .select(KyberPreKeyTable.KEY_ID) - .from(KyberPreKeyTable.TABLE_NAME) - .where("${KyberPreKeyTable.ACCOUNT_ID} = ?", getAliceServiceId().toString()) - .run() - .readToSingleInt(-1) - - val selfSignedKyberPreKeyRecord = SignalDatabase.kyberPreKeys.get(getAliceServiceId(), selfSignedKyberPreKeyId)!!.record - - return PreKeyBundle( - SignalStore.account.registrationId, - 1, - selfPreKeyId, - selfPreKeyRecord.keyPair.publicKey, - selfSignedPreKeyId, - selfSignedPreKeyRecord.keyPair.publicKey, - selfSignedPreKeyRecord.signature, - getAlicePublicKey(), - selfSignedKyberPreKeyId, - selfSignedKyberPreKeyRecord.keyPair.publicKey, - selfSignedKyberPreKeyRecord.signature - ) - } - - private fun getAliceProtocolAddress(): SignalProtocolAddress { - return SignalProtocolAddress(SignalStore.account.requireAci().toString(), 1) - } - - private fun getAlicePublicKey(): IdentityKey { - return SignalStore.account.aciIdentityKey.publicKey - } - - private fun getAliceProfileKey(): ProfileKey { - return ProfileKeyUtil.getSelfProfileKey() - } - - private fun getAliceUnidentifiedAccess(): SealedSenderAccess? { - return FakeClientHelpers.getSealedSenderAccess(getAliceProfileKey(), senderCertificate) - } - - private class BobSignalServiceAccountDataStore(private val registrationId: Int, private val identityKeyPair: IdentityKeyPair) : SignalServiceAccountDataStore { - private var aliceSessionRecord: SessionRecord? = null - - override fun getIdentityKeyPair(): IdentityKeyPair = identityKeyPair - - override fun getLocalRegistrationId(): Int = registrationId - override fun isTrustedIdentity(address: SignalProtocolAddress?, identityKey: IdentityKey?, direction: IdentityKeyStore.Direction?): Boolean = true - override fun loadSession(address: SignalProtocolAddress?): SessionRecord = aliceSessionRecord ?: SessionRecord() - override fun saveIdentity(address: SignalProtocolAddress?, identityKey: IdentityKey?): IdentityKeyStore.IdentityChange = IdentityChange.NEW_OR_UNCHANGED - override fun storeSession(address: SignalProtocolAddress?, record: SessionRecord?) { - aliceSessionRecord = record - } - override fun getSubDeviceSessions(name: String?): List = emptyList() - override fun containsSession(address: SignalProtocolAddress?): Boolean = aliceSessionRecord != null - override fun getIdentity(address: SignalProtocolAddress?): IdentityKey = SignalStore.account.aciIdentityKey.publicKey - override fun loadPreKey(preKeyId: Int): PreKeyRecord = throw UnsupportedOperationException() - override fun storePreKey(preKeyId: Int, record: PreKeyRecord?) = throw UnsupportedOperationException() - override fun containsPreKey(preKeyId: Int): Boolean = throw UnsupportedOperationException() - override fun removePreKey(preKeyId: Int) = throw UnsupportedOperationException() - override fun loadExistingSessions(addresses: MutableList?): MutableList = throw UnsupportedOperationException() - override fun deleteSession(address: SignalProtocolAddress?) = throw UnsupportedOperationException() - override fun deleteAllSessions(name: String?) = throw UnsupportedOperationException() - override fun loadSignedPreKey(signedPreKeyId: Int): SignedPreKeyRecord = throw UnsupportedOperationException() - override fun loadSignedPreKeys(): MutableList = throw UnsupportedOperationException() - override fun storeSignedPreKey(signedPreKeyId: Int, record: SignedPreKeyRecord?) = throw UnsupportedOperationException() - override fun containsSignedPreKey(signedPreKeyId: Int): Boolean = throw UnsupportedOperationException() - override fun removeSignedPreKey(signedPreKeyId: Int) = throw UnsupportedOperationException() - override fun loadKyberPreKey(kyberPreKeyId: Int): KyberPreKeyRecord = throw UnsupportedOperationException() - override fun loadKyberPreKeys(): MutableList = throw UnsupportedOperationException() - override fun storeKyberPreKey(kyberPreKeyId: Int, record: KyberPreKeyRecord?) = throw UnsupportedOperationException() - override fun containsKyberPreKey(kyberPreKeyId: Int): Boolean = throw UnsupportedOperationException() - override fun markKyberPreKeyUsed(kyberPreKeyId: Int, signedPreKeyId: Int, baseKey: ECPublicKey) = throw UnsupportedOperationException() - override fun deleteAllStaleOneTimeEcPreKeys(threshold: Long, minCount: Int) = throw UnsupportedOperationException() - override fun markAllOneTimeEcPreKeysStaleIfNecessary(staleTime: Long) = throw UnsupportedOperationException() - override fun storeSenderKey(sender: SignalProtocolAddress?, distributionId: UUID?, record: SenderKeyRecord?) = throw UnsupportedOperationException() - override fun loadSenderKey(sender: SignalProtocolAddress?, distributionId: UUID?): SenderKeyRecord = throw UnsupportedOperationException() - override fun archiveSession(address: SignalProtocolAddress?) = throw UnsupportedOperationException() - override fun getAllAddressesWithActiveSessions(addressNames: MutableList?): MutableMap = throw UnsupportedOperationException() - override fun getSenderKeySharedWith(distributionId: DistributionId?): MutableSet = throw UnsupportedOperationException() - override fun markSenderKeySharedWith(distributionId: DistributionId?, addresses: MutableCollection?) = throw UnsupportedOperationException() - override fun clearSenderKeySharedWith(addresses: MutableCollection?) = throw UnsupportedOperationException() - override fun storeLastResortKyberPreKey(kyberPreKeyId: Int, kyberPreKeyRecord: KyberPreKeyRecord) = throw UnsupportedOperationException() - override fun removeKyberPreKey(kyberPreKeyId: Int) = throw UnsupportedOperationException() - override fun markAllOneTimeKyberPreKeysStaleIfNecessary(staleTime: Long) = throw UnsupportedOperationException() - override fun deleteAllStaleOneTimeKyberPreKeys(threshold: Long, minCount: Int) = throw UnsupportedOperationException() - override fun loadLastResortKyberPreKeys(): List = throw UnsupportedOperationException() - override fun isMultiDevice(): Boolean = throw UnsupportedOperationException() - } -} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/FakeClientHelpers.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/FakeClientHelpers.kt deleted file mode 100644 index 6f71841b82..0000000000 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/FakeClientHelpers.kt +++ /dev/null @@ -1,71 +0,0 @@ -package org.thoughtcrime.securesms.testing - -import okio.ByteString.Companion.toByteString -import org.signal.core.models.ServiceId -import org.signal.core.util.Base64 -import org.signal.core.util.toByteArray -import org.signal.libsignal.metadata.certificate.CertificateValidator -import org.signal.libsignal.metadata.certificate.SenderCertificate -import org.signal.libsignal.metadata.certificate.ServerCertificate -import org.signal.libsignal.protocol.ecc.ECKeyPair -import org.signal.libsignal.protocol.ecc.ECPublicKey -import org.signal.libsignal.zkgroup.profiles.ProfileKey -import org.thoughtcrime.securesms.messages.SignalServiceProtoUtil.buildWith -import org.whispersystems.signalservice.api.crypto.ContentHint -import org.whispersystems.signalservice.api.crypto.EnvelopeContent -import org.whispersystems.signalservice.api.crypto.SealedSenderAccess -import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess -import org.whispersystems.signalservice.internal.push.Content -import org.whispersystems.signalservice.internal.push.DataMessage -import org.whispersystems.signalservice.internal.push.Envelope -import org.whispersystems.signalservice.internal.push.OutgoingPushMessage -import java.util.Optional -import java.util.UUID - -object FakeClientHelpers { - - val noOpCertificateValidator = object : CertificateValidator(ECKeyPair.generate().publicKey) { - override fun validate(certificate: SenderCertificate, validationTime: Long) = Unit - } - - fun createCertificateFor(trustRoot: ECKeyPair, uuid: UUID, e164: String, deviceId: Int, identityKey: ECPublicKey, expires: Long): SenderCertificate { - val serverKey: ECKeyPair = ECKeyPair.generate() - val serverCertificate = ServerCertificate(trustRoot.privateKey, 1, serverKey.publicKey) - return serverCertificate.issue(serverKey.privateKey, uuid.toString(), Optional.of(e164), deviceId, identityKey, expires) - } - - fun getSealedSenderAccess(theirProfileKey: ProfileKey, senderCertificate: SenderCertificate): SealedSenderAccess? { - val themUnidentifiedAccessKey = UnidentifiedAccess(UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey), senderCertificate.serialized, false) - - return SealedSenderAccess.forIndividual(themUnidentifiedAccessKey) - } - - fun encryptedTextMessage(now: Long, message: String = "Test body message"): EnvelopeContent { - val content = Content.Builder().apply { - dataMessage( - DataMessage.Builder().buildWith { - body = message - timestamp = now - } - ) - } - return EnvelopeContent.encrypted(content.build(), ContentHint.RESENDABLE, Optional.empty()) - } - - fun OutgoingPushMessage.toEnvelope(timestamp: Long, destination: ServiceId): Envelope { - val serverGuid = UUID.randomUUID() - return Envelope.Builder() - .type(Envelope.Type.fromValue(this.type)) - .sourceDevice(1) - .timestamp(timestamp) - .serverTimestamp(timestamp + 1) - .destinationServiceId(destination.toString()) - .destinationServiceIdBinary(destination.toByteString()) - .serverGuid(serverGuid.toString()) - .serverGuidBinary(serverGuid.toByteArray().toByteString()) - .content(Base64.decode(this.content).toByteString()) - .urgent(true) - .story(false) - .build() - } -}