From a91a13cead03078025651c666b8aee10356084c4 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Thu, 2 Feb 2023 10:10:00 -0500 Subject: [PATCH] Introduce Wire for proto codegen. --- app/build.gradle | 12 ++ .../absbackup/backupables/KbsAuthTokens.kt | 12 +- .../database/loaders/DeviceListLoader.java | 13 +- .../securesms/emoji/JumboEmoji.kt | 6 +- .../secondary/DeviceNameCipher.kt | 15 +- .../{proto => protowire}/DeviceName.proto | 3 +- app/src/main/{proto => protowire}/Emoji.proto | 0 .../ExternalBackups.proto | 5 +- .../secondary/DeviceNameCipherTest.kt | 4 +- build.gradle | 7 + gradle/verification-metadata.xml | 169 ++++++++++++++++++ 11 files changed, 215 insertions(+), 31 deletions(-) rename app/src/main/{proto => protowire}/DeviceName.proto (71%) rename app/src/main/{proto => protowire}/Emoji.proto (100%) rename app/src/main/{proto => protowire}/ExternalBackups.proto (53%) diff --git a/app/build.gradle b/app/build.gradle index 385e932ec6..69bebf0414 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,10 @@ apply from: 'translations.gradle' apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'app.cash.exhaustive' apply plugin: 'kotlin-parcelize' +apply plugin: 'com.squareup.wire' apply from: 'static-ips.gradle' + repositories { maven { url "https://raw.githubusercontent.com/signalapp/maven/master/sqlcipher/release/" @@ -47,6 +49,16 @@ protobuf { } } +wire { + kotlin { + javaInterop = true + } + + sourcePath { + srcDir 'src/main/protowire' + } +} + ktlint { // Use a newer version to resolve https://github.com/JLLeitschuh/ktlint-gradle/issues/507 version = "0.43.2" diff --git a/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/KbsAuthTokens.kt b/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/KbsAuthTokens.kt index c0919cd8e8..b510845ac4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/KbsAuthTokens.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/absbackup/backupables/KbsAuthTokens.kt @@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.absbackup.backupables import com.google.protobuf.InvalidProtocolBufferException import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.absbackup.AndroidBackupItem -import org.thoughtcrime.securesms.absbackup.ExternalBackupProtos +import org.thoughtcrime.securesms.absbackup.protos.KbsAuthToken import org.thoughtcrime.securesms.keyvalue.SignalStore /** @@ -18,10 +18,8 @@ object KbsAuthTokens : AndroidBackupItem { override fun getDataForBackup(): ByteArray { val registrationRecoveryTokenList = SignalStore.kbsValues().kbsAuthTokenList - val proto = ExternalBackupProtos.KbsAuthToken.newBuilder() - .addAllToken(registrationRecoveryTokenList) - .build() - return proto.toByteArray() + val proto = KbsAuthToken(tokens = registrationRecoveryTokenList) + return proto.encode() } override fun restoreData(data: ByteArray) { @@ -30,9 +28,9 @@ object KbsAuthTokens : AndroidBackupItem { } try { - val proto = ExternalBackupProtos.KbsAuthToken.parseFrom(data) + val proto = KbsAuthToken.ADAPTER.decode(data) - SignalStore.kbsValues().putAuthTokenList(proto.tokenList) + SignalStore.kbsValues().putAuthTokenList(proto.tokens) } catch (e: InvalidProtocolBufferException) { Log.w(TAG, "Cannot restore KbsAuthToken from backup service.") } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java b/app/src/main/java/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java index 4b06bb5773..5a7c3656a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java @@ -29,13 +29,14 @@ import java.security.MessageDigest; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Objects; import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import static org.thoughtcrime.securesms.devicelist.DeviceNameProtos.DeviceName; +import org.thoughtcrime.securesms.devicelist.protos.DeviceName; public class DeviceListLoader extends AsyncLoader> { @@ -71,9 +72,9 @@ public class DeviceListLoader extends AsyncLoader> { throw new IOException("Invalid DeviceInfo name."); } - DeviceName deviceName = DeviceName.parseFrom(Base64.decode(deviceInfo.getName())); + DeviceName deviceName = DeviceName.ADAPTER.decode(Base64.decode(deviceInfo.getName())); - if (!deviceName.hasCiphertext() || !deviceName.hasEphemeralPublic() || !deviceName.hasSyntheticIv()) { + if (deviceName.ciphertext == null || deviceName.ephemeralPublic == null || deviceName.syntheticIv == null) { throw new IOException("Got a DeviceName that wasn't properly populated."); } @@ -90,10 +91,10 @@ public class DeviceListLoader extends AsyncLoader> { @VisibleForTesting public static byte[] decryptName(DeviceName deviceName, IdentityKeyPair identityKeyPair) throws InvalidKeyException, GeneralSecurityException { - byte[] syntheticIv = deviceName.getSyntheticIv().toByteArray(); - byte[] cipherText = deviceName.getCiphertext().toByteArray(); + byte[] syntheticIv = Objects.requireNonNull(deviceName.syntheticIv).toByteArray(); + byte[] cipherText = Objects.requireNonNull(deviceName.ciphertext).toByteArray(); ECPrivateKey identityKey = identityKeyPair.getPrivateKey(); - ECPublicKey ephemeralPublic = Curve.decodePoint(deviceName.getEphemeralPublic().toByteArray(), 0); + ECPublicKey ephemeralPublic = Curve.decodePoint(Objects.requireNonNull(deviceName.ephemeralPublic).toByteArray(), 0); byte[] masterSecret = Curve.calculateAgreement(ephemeralPublic, identityKey); Mac mac = Mac.getInstance("HmacSHA256"); diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/JumboEmoji.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/JumboEmoji.kt index fd386b5ada..715bfd91a3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/emoji/JumboEmoji.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/emoji/JumboEmoji.kt @@ -116,13 +116,13 @@ object JumboEmoji { Log.i(TAG, "No file for emoji, downloading jumbo") EmojiDownloader.streamFileFromRemote(version, version.density, archiveName) { stream -> stream.use { remote -> - val jumbomojiPack = JumbomojiPack.parseFrom(remote) + val jumbomojiPack = JumbomojiPack.ADAPTER.decode(remote) - jumbomojiPack.itemsList.forEach { jumbo -> + jumbomojiPack.items.forEach { jumbo -> val emojiNameEntry = EmojiFiles.Name(jumbo.name, UUID.randomUUID()) val outputStream = EmojiFiles.openForWriting(applicationContext, version, emojiNameEntry.uuid) - outputStream.use { jumbo.image.writeTo(it) } + outputStream.use { jumbo.image.write(it) } jumbos = EmojiFiles.JumboCollection.append(applicationContext, jumbos, emojiNameEntry) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipher.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipher.kt index e9d5db0237..a02b7016a5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipher.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipher.kt @@ -1,10 +1,10 @@ package org.thoughtcrime.securesms.registration.secondary -import com.google.protobuf.ByteString +import okio.ByteString.Companion.toByteString import org.signal.libsignal.protocol.IdentityKeyPair import org.signal.libsignal.protocol.ecc.Curve import org.signal.libsignal.protocol.ecc.ECKeyPair -import org.thoughtcrime.securesms.devicelist.DeviceNameProtos +import org.thoughtcrime.securesms.devicelist.protos.DeviceName import java.nio.charset.Charset import javax.crypto.Cipher import javax.crypto.Mac @@ -30,12 +30,11 @@ object DeviceNameCipher { cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(ByteArray(16))) val cipherText = cipher.doFinal(plaintext) - return DeviceNameProtos.DeviceName.newBuilder() - .setEphemeralPublic(ByteString.copyFrom(ephemeralKeyPair.publicKey.serialize())) - .setSyntheticIv(ByteString.copyFrom(syntheticIv)) - .setCiphertext(ByteString.copyFrom(cipherText)) - .build() - .toByteArray() + return DeviceName( + ephemeralPublic = ephemeralKeyPair.publicKey.serialize().toByteString(), + syntheticIv = syntheticIv.toByteString(), + ciphertext = cipherText.toByteString() + ).encode() } private fun computeCipherKey(masterSecret: ByteArray, syntheticIv: ByteArray): ByteArray { diff --git a/app/src/main/proto/DeviceName.proto b/app/src/main/protowire/DeviceName.proto similarity index 71% rename from app/src/main/proto/DeviceName.proto rename to app/src/main/protowire/DeviceName.proto index ef00884266..c3139b20e8 100644 --- a/app/src/main/proto/DeviceName.proto +++ b/app/src/main/protowire/DeviceName.proto @@ -8,8 +8,7 @@ syntax = "proto2"; package signalservice; -option java_package = "org.thoughtcrime.securesms.devicelist"; -option java_outer_classname = "DeviceNameProtos"; +option java_package = "org.thoughtcrime.securesms.devicelist.protos"; message DeviceName { optional bytes ephemeralPublic = 1; diff --git a/app/src/main/proto/Emoji.proto b/app/src/main/protowire/Emoji.proto similarity index 100% rename from app/src/main/proto/Emoji.proto rename to app/src/main/protowire/Emoji.proto diff --git a/app/src/main/proto/ExternalBackups.proto b/app/src/main/protowire/ExternalBackups.proto similarity index 53% rename from app/src/main/proto/ExternalBackups.proto rename to app/src/main/protowire/ExternalBackups.proto index a59f54974d..abf7bbc85d 100644 --- a/app/src/main/proto/ExternalBackups.proto +++ b/app/src/main/protowire/ExternalBackups.proto @@ -8,9 +8,8 @@ syntax = "proto3"; package signal; -option java_package = "org.thoughtcrime.securesms.absbackup"; -option java_outer_classname = "ExternalBackupProtos"; +option java_package = "org.thoughtcrime.securesms.absbackup.protos"; message KbsAuthToken { - repeated string token = 1; + repeated string tokens = 1; } \ No newline at end of file diff --git a/app/src/test/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipherTest.kt b/app/src/test/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipherTest.kt index eee71df506..9e9cad9706 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipherTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/registration/secondary/DeviceNameCipherTest.kt @@ -5,7 +5,7 @@ import org.hamcrest.Matchers.`is` import org.junit.Test import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.loaders.DeviceListLoader -import org.thoughtcrime.securesms.devicelist.DeviceNameProtos +import org.thoughtcrime.securesms.devicelist.protos.DeviceName import java.nio.charset.Charset class DeviceNameCipherTest { @@ -17,7 +17,7 @@ class DeviceNameCipherTest { val encryptedDeviceName = DeviceNameCipher.encryptDeviceName(deviceName.toByteArray(Charset.forName("UTF-8")), identityKeyPair) - val plaintext = DeviceListLoader.decryptName(DeviceNameProtos.DeviceName.parseFrom(encryptedDeviceName), identityKeyPair) + val plaintext = DeviceListLoader.decryptName(DeviceName.ADAPTER.decode(encryptedDeviceName), identityKeyPair) assertThat(String(plaintext, Charset.forName("UTF-8")), `is`(deviceName)) } diff --git a/build.gradle b/build.gradle index d5b26c362f..6f245c336b 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,13 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jlleitschuh.gradle:ktlint-gradle:10.2.1" classpath 'app.cash.exhaustive:exhaustive-gradle:0.1.1' + classpath ('com.squareup.wire:wire-gradle-plugin:4.4.3') { + exclude group: 'com.squareup.wire', module: 'wire-swift-generator' + exclude group: 'com.squareup.wire', module: 'wire-grpc-client' + exclude group: 'com.squareup.wire', module: 'wire-grpc-jvm' + exclude group: 'com.squareup.wire', module: 'wire-grpc-server-generator' + exclude group: 'io.outfoxx', module: 'swiftpoet' + } } } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 39f9167727..eb9325d6db 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1501,6 +1501,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -1948,6 +1956,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -2093,6 +2106,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -2473,6 +2491,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -2579,6 +2605,19 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + + + + + + @@ -2594,6 +2633,88 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3702,6 +3823,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -3817,6 +3943,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -3867,11 +3998,21 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + + + @@ -3917,6 +4058,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -3962,6 +4108,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -4133,11 +4284,24 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + + + + + + @@ -4628,6 +4792,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + +