Support PNI prekeys.

This commit is contained in:
Greyson Parrelli
2022-02-01 14:09:04 -05:00
parent db534cd376
commit e8ad1e8ed1
32 changed files with 808 additions and 532 deletions

View File

@@ -8,6 +8,7 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.crypto.MasterCipher
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
import org.thoughtcrime.securesms.crypto.storage.PreKeyMetadataStore
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.recipients.Recipient
@@ -18,9 +19,11 @@ import org.thoughtcrime.securesms.util.Util
import org.whispersystems.libsignal.IdentityKey
import org.whispersystems.libsignal.IdentityKeyPair
import org.whispersystems.libsignal.ecc.Curve
import org.whispersystems.libsignal.util.Medium
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.PNI
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import java.security.SecureRandom
internal class AccountValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) {
@@ -35,10 +38,22 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
private const val KEY_FCM_TOKEN_LAST_SET_TIME = "account.fcm_token_last_set_time"
private const val KEY_DEVICE_NAME = "account.device_name"
private const val KEY_DEVICE_ID = "account.device_id"
private const val KEY_ACI_IDENTITY_PUBLIC_KEY = "account.aci_identity_public_key"
private const val KEY_ACI_IDENTITY_PRIVATE_KEY = "account.aci_identity_private_key"
private const val KEY_ACI_SIGNED_PREKEY_REGISTERED = "account.aci_signed_prekey_registered"
private const val KEY_ACI_NEXT_SIGNED_PREKEY_ID = "account.aci_next_signed_prekey_id"
private const val KEY_ACI_ACTIVE_SIGNED_PREKEY_ID = "account.aci_active_signed_prekey_id"
private const val KEY_ACI_SIGNED_PREKEY_FAILURE_COUNT = "account.aci_signed_prekey_failure_count"
private const val KEY_ACI_NEXT_ONE_TIME_PREKEY_ID = "account.aci_next_one_time_prekey_id"
private const val KEY_PNI_IDENTITY_PUBLIC_KEY = "account.pni_identity_public_key"
private const val KEY_PNI_IDENTITY_PRIVATE_KEY = "account.pni_identity_private_key"
private const val KEY_PNI_SIGNED_PREKEY_REGISTERED = "account.pni_signed_prekey_registered"
private const val KEY_PNI_NEXT_SIGNED_PREKEY_ID = "account.pni_next_signed_prekey_id"
private const val KEY_PNI_ACTIVE_SIGNED_PREKEY_ID = "account.pni_active_signed_prekey_id"
private const val KEY_PNI_SIGNED_PREKEY_FAILURE_COUNT = "account.pni_signed_prekey_failure_count"
private const val KEY_PNI_NEXT_ONE_TIME_PREKEY_ID = "account.pni_next_one_time_prekey_id"
@VisibleForTesting
const val KEY_E164 = "account.e164"
@@ -102,9 +117,7 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
}
/** A randomly-generated value that represents this registration instance. Helps the server know if you reinstalled. */
var registrationId: Int
get() = getInteger(KEY_REGISTRATION_ID, 0)
set(value) = putInteger(KEY_REGISTRATION_ID, value)
var registrationId: Int by integerValue(KEY_REGISTRATION_ID, 0)
/** The identity key pair for the ACI identity. */
val aciIdentityKey: IdentityKeyPair
@@ -147,8 +160,8 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
val key: IdentityKeyPair = IdentityKeyUtil.generateIdentityKeyPair()
store
.beginWrite()
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, key.publicKey.serialize())
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, key.privateKey.serialize())
.putBlob(KEY_PNI_IDENTITY_PUBLIC_KEY, key.publicKey.serialize())
.putBlob(KEY_PNI_IDENTITY_PRIVATE_KEY, key.privateKey.serialize())
.commit()
}
@@ -174,11 +187,27 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, Base64.decode(base64))
}
@get:JvmName("aciPreKeys")
val aciPreKeys: PreKeyMetadataStore = object : PreKeyMetadataStore {
override var nextSignedPreKeyId: Int by integerValue(KEY_ACI_NEXT_SIGNED_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
override var activeSignedPreKeyId: Int by integerValue(KEY_ACI_ACTIVE_SIGNED_PREKEY_ID, -1)
override var isSignedPreKeyRegistered: Boolean by booleanValue(KEY_ACI_SIGNED_PREKEY_REGISTERED, false)
override var signedPreKeyFailureCount: Int by integerValue(KEY_ACI_SIGNED_PREKEY_FAILURE_COUNT, 0)
override var nextOneTimePreKeyId: Int by integerValue(KEY_ACI_NEXT_ONE_TIME_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
}
@get:JvmName("pniPreKeys")
val pniPreKeys: PreKeyMetadataStore = object : PreKeyMetadataStore {
override var nextSignedPreKeyId: Int by integerValue(KEY_PNI_NEXT_SIGNED_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
override var activeSignedPreKeyId: Int by integerValue(KEY_PNI_ACTIVE_SIGNED_PREKEY_ID, -1)
override var isSignedPreKeyRegistered: Boolean by booleanValue(KEY_PNI_SIGNED_PREKEY_REGISTERED, false)
override var signedPreKeyFailureCount: Int by integerValue(KEY_PNI_SIGNED_PREKEY_FAILURE_COUNT, 0)
override var nextOneTimePreKeyId: Int by integerValue(KEY_PNI_NEXT_ONE_TIME_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
}
/** Indicates whether the user has the ability to receive FCM messages. Largely coupled to whether they have Play Service. */
var fcmEnabled: Boolean
@JvmName("isFcmEnabled")
get() = getBoolean(KEY_FCM_ENABLED, false)
set(value) = putBoolean(KEY_FCM_ENABLED, value)
@get:JvmName("isFcmEnabled")
var fcmEnabled: Boolean by booleanValue(KEY_FCM_ENABLED, false)
/** The FCM token, which allows the server to send us FCM messages. */
var fcmToken: String?
@@ -249,6 +278,7 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
ApplicationDependencies.getGroupsV2Authorization().clear()
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private fun migrateFromSharedPrefsV1(context: Context) {
Log.i(TAG, "[V1] Migrating account values from shared prefs.")
@@ -263,23 +293,24 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
putLong(KEY_FCM_TOKEN_LAST_SET_TIME, TextSecurePreferences.getLongPreference(context, "pref_gcm_registration_id_last_set_time", 0))
}
/** Do not alter. If you need to migrate more stuff, create a new method. */
private fun migrateFromSharedPrefsV2(context: Context) {
Log.i(TAG, "[V2] Migrating account values from shared prefs.")
val masterSecretPrefs: SharedPreferences = context.getSharedPreferences("SecureSMS-Preferences", 0)
val defaultPrefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val storeWriter: KeyValueStore.Writer = store.beginWrite()
if (masterSecretPrefs.hasStringData("pref_identity_public_v3")) {
Log.i(TAG, "Migrating modern identity key.")
val identityPublic = Base64.decode(masterSecretPrefs.getString("pref_identity_public_v3", null)!!)
val identityPrivate = Base64.decode(masterSecretPrefs.getString("pref_identity_private_v3", null)!!)
store
.beginWrite()
storeWriter
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, identityPublic)
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, identityPrivate)
.commit()
} else if (masterSecretPrefs.hasStringData("pref_identity_public_curve25519")) {
Log.i(TAG, "Migrating legacy identity key.")
@@ -287,15 +318,21 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
val identityPublic = Base64.decode(masterSecretPrefs.getString("pref_identity_public_curve25519", null)!!)
val identityPrivate = masterCipher.decryptKey(Base64.decode(masterSecretPrefs.getString("pref_identity_private_curve25519", null)!!)).serialize()
store
.beginWrite()
storeWriter
.putBlob(KEY_ACI_IDENTITY_PUBLIC_KEY, identityPublic)
.putBlob(KEY_ACI_IDENTITY_PRIVATE_KEY, identityPrivate)
.commit()
} else {
Log.w(TAG, "No pre-existing identity key! No migration.")
}
storeWriter
.putInteger(KEY_ACI_NEXT_SIGNED_PREKEY_ID, defaultPrefs.getInt("pref_next_signed_pre_key_id", SecureRandom().nextInt(Medium.MAX_VALUE)))
.putInteger(KEY_ACI_ACTIVE_SIGNED_PREKEY_ID, defaultPrefs.getInt("pref_active_signed_pre_key_id", -1))
.putInteger(KEY_ACI_NEXT_ONE_TIME_PREKEY_ID, defaultPrefs.getInt("pref_next_pre_key_id", SecureRandom().nextInt(Medium.MAX_VALUE)))
.putInteger(KEY_ACI_SIGNED_PREKEY_FAILURE_COUNT, defaultPrefs.getInt("pref_signed_prekey_failure_count", 0))
.putBoolean(KEY_ACI_SIGNED_PREKEY_REGISTERED, defaultPrefs.getBoolean("pref_signed_prekey_registered", false))
.commit()
masterSecretPrefs
.edit()
.remove("pref_identity_public_v3")
@@ -308,6 +345,11 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
.edit()
.remove("pref_local_uuid")
.remove("pref_identity_public_v3")
.remove("pref_next_signed_pre_key_id")
.remove("pref_active_signed_pre_key_id")
.remove("pref_signed_prekey_failure_count")
.remove("pref_signed_prekey_registered")
.remove("pref_next_pre_key_id")
.remove("pref_gcm_password")
.remove("pref_gcm_registered")
.remove("pref_local_registration_id")

View File

@@ -3,102 +3,102 @@ package org.thoughtcrime.securesms.keyvalue
import kotlin.reflect.KProperty
internal fun SignalStoreValues.longValue(key: String, default: Long): SignalStoreValueDelegate<Long> {
return LongValue(key, default)
return LongValue(key, default, this.store)
}
internal fun SignalStoreValues.booleanValue(key: String, default: Boolean): SignalStoreValueDelegate<Boolean> {
return BooleanValue(key, default)
return BooleanValue(key, default, this.store)
}
internal fun <T : String?> SignalStoreValues.stringValue(key: String, default: T): SignalStoreValueDelegate<T> {
return StringValue(key, default)
return StringValue(key, default, this.store)
}
internal fun SignalStoreValues.integerValue(key: String, default: Int): SignalStoreValueDelegate<Int> {
return IntValue(key, default)
return IntValue(key, default, this.store)
}
internal fun SignalStoreValues.floatValue(key: String, default: Float): SignalStoreValueDelegate<Float> {
return FloatValue(key, default)
return FloatValue(key, default, this.store)
}
internal fun SignalStoreValues.blobValue(key: String, default: ByteArray): SignalStoreValueDelegate<ByteArray> {
return BlobValue(key, default)
return BlobValue(key, default, this.store)
}
/**
* Kotlin delegate that serves as a base for all other value types. This allows us to only expose this sealed
* class to callers and protect the individual implementations as private behind the various extension functions.
*/
sealed class SignalStoreValueDelegate<T> {
sealed class SignalStoreValueDelegate<T>(private val store: KeyValueStore) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return getValue(thisRef as SignalStoreValues)
return getValue(store)
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
setValue(thisRef as SignalStoreValues, value)
setValue(store, value)
}
internal abstract fun getValue(values: SignalStoreValues): T
internal abstract fun setValue(values: SignalStoreValues, value: T)
internal abstract fun getValue(values: KeyValueStore): T
internal abstract fun setValue(values: KeyValueStore, value: T)
}
private class LongValue(private val key: String, private val default: Long) : SignalStoreValueDelegate<Long>() {
override fun getValue(values: SignalStoreValues): Long {
private class LongValue(private val key: String, private val default: Long, store: KeyValueStore) : SignalStoreValueDelegate<Long>(store) {
override fun getValue(values: KeyValueStore): Long {
return values.getLong(key, default)
}
override fun setValue(values: SignalStoreValues, value: Long) {
values.putLong(key, value)
override fun setValue(values: KeyValueStore, value: Long) {
values.beginWrite().putLong(key, value).apply()
}
}
private class BooleanValue(private val key: String, private val default: Boolean) : SignalStoreValueDelegate<Boolean>() {
override fun getValue(values: SignalStoreValues): Boolean {
private class BooleanValue(private val key: String, private val default: Boolean, store: KeyValueStore) : SignalStoreValueDelegate<Boolean>(store) {
override fun getValue(values: KeyValueStore): Boolean {
return values.getBoolean(key, default)
}
override fun setValue(values: SignalStoreValues, value: Boolean) {
values.putBoolean(key, value)
override fun setValue(values: KeyValueStore, value: Boolean) {
values.beginWrite().putBoolean(key, value).apply()
}
}
private class StringValue<T : String?>(private val key: String, private val default: T) : SignalStoreValueDelegate<T>() {
override fun getValue(values: SignalStoreValues): T {
private class StringValue<T : String?>(private val key: String, private val default: T, store: KeyValueStore) : SignalStoreValueDelegate<T>(store) {
override fun getValue(values: KeyValueStore): T {
return values.getString(key, default) as T
}
override fun setValue(values: SignalStoreValues, value: T) {
values.putString(key, value)
override fun setValue(values: KeyValueStore, value: T) {
values.beginWrite().putString(key, value).apply()
}
}
private class IntValue(private val key: String, private val default: Int) : SignalStoreValueDelegate<Int>() {
override fun getValue(values: SignalStoreValues): Int {
private class IntValue(private val key: String, private val default: Int, store: KeyValueStore) : SignalStoreValueDelegate<Int>(store) {
override fun getValue(values: KeyValueStore): Int {
return values.getInteger(key, default)
}
override fun setValue(values: SignalStoreValues, value: Int) {
values.putInteger(key, value)
override fun setValue(values: KeyValueStore, value: Int) {
values.beginWrite().putInteger(key, value).apply()
}
}
private class FloatValue(private val key: String, private val default: Float) : SignalStoreValueDelegate<Float>() {
override fun getValue(values: SignalStoreValues): Float {
private class FloatValue(private val key: String, private val default: Float, store: KeyValueStore) : SignalStoreValueDelegate<Float>(store) {
override fun getValue(values: KeyValueStore): Float {
return values.getFloat(key, default)
}
override fun setValue(values: SignalStoreValues, value: Float) {
values.putFloat(key, value)
override fun setValue(values: KeyValueStore, value: Float) {
values.beginWrite().putFloat(key, value).apply()
}
}
private class BlobValue(private val key: String, private val default: ByteArray) : SignalStoreValueDelegate<ByteArray>() {
override fun getValue(values: SignalStoreValues): ByteArray {
private class BlobValue(private val key: String, private val default: ByteArray, store: KeyValueStore) : SignalStoreValueDelegate<ByteArray>(store) {
override fun getValue(values: KeyValueStore): ByteArray {
return values.getBlob(key, default)
}
override fun setValue(values: SignalStoreValues, value: ByteArray) {
values.putBlob(key, value)
override fun setValue(values: KeyValueStore, value: ByteArray) {
values.beginWrite().putBlob(key, value).apply()
}
}