Update to the new username link spec.

This commit is contained in:
Greyson Parrelli
2023-08-25 09:33:57 -04:00
parent a6dd4345ab
commit 8a93814bac
47 changed files with 1283 additions and 463 deletions

View File

@@ -26,6 +26,9 @@ import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.api.push.ServiceId.PNI
import org.whispersystems.signalservice.api.push.ServiceIds
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.api.push.UsernameLinkComponents
import org.whispersystems.signalservice.api.util.UuidUtil
import org.whispersystems.signalservice.api.util.toByteArray
import java.security.SecureRandom
internal class AccountValues internal constructor(store: KeyValueStore) : SignalStoreValues(store) {
@@ -64,6 +67,11 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
private const val KEY_PNI_LAST_RESORT_KYBER_PREKEY_ID = "account.pni_last_resort_kyber_prekey_id"
private const val KEY_PNI_LAST_RESORT_KYBER_PREKEY_ROTATION_TIME = "account.pni_last_resort_kyber_prekey_rotation_time"
private const val KEY_USERNAME = "account.username"
private const val KEY_USERNAME_LINK_ENTROPY = "account.username_link_entropy"
private const val KEY_USERNAME_LINK_SERVER_ID = "account.username_link_server_id"
private const val KEY_USERNAME_OUT_OF_SYNC = "phoneNumberPrivacy.usernameOutOfSync"
@VisibleForTesting
const val KEY_E164 = "account.e164"
@@ -100,7 +108,9 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
KEY_ACI_IDENTITY_PUBLIC_KEY,
KEY_ACI_IDENTITY_PRIVATE_KEY,
KEY_PNI_IDENTITY_PUBLIC_KEY,
KEY_PNI_IDENTITY_PRIVATE_KEY
KEY_PNI_IDENTITY_PRIVATE_KEY,
KEY_USERNAME,
KEY_USERNAME_LINK_SERVER_ID
)
}
@@ -351,6 +361,36 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
val isLinkedDevice: Boolean
get() = !isPrimaryDevice
/** The local user's full username (nickname.discriminator), if set. */
var username: String? by stringValue(KEY_USERNAME, null)
/** The local user's username link components, if set. */
var usernameLink: UsernameLinkComponents?
get() {
val entropy: ByteArray? = getBlob(KEY_USERNAME_LINK_ENTROPY, null)
val serverId: ByteArray? = getBlob(KEY_USERNAME_LINK_SERVER_ID, null)
return if (entropy != null && serverId != null) {
val serverIdUuid = UuidUtil.parseOrThrow(serverId)
UsernameLinkComponents(entropy, serverIdUuid)
} else {
null
}
}
set(value) {
store
.beginWrite()
.putBlob(KEY_USERNAME_LINK_ENTROPY, value?.entropy)
.putBlob(KEY_USERNAME_LINK_SERVER_ID, value?.serverId?.toByteArray())
.apply()
}
/**
* There are some cases where our username may fall out of sync with the service. In particular, we may get a new value for our username from
* storage service but then find that it doesn't match what's on the service.
*/
var usernameOutOfSync: Boolean by booleanValue(KEY_USERNAME_OUT_OF_SYNC, false)
private fun clearLocalCredentials() {
putString(KEY_SERVICE_PASSWORD, Util.getSecret(18))

View File

@@ -11,10 +11,9 @@ import java.util.List;
public final class PhoneNumberPrivacyValues extends SignalStoreValues {
public static final String SHARING_MODE = "phoneNumberPrivacy.sharingMode";
public static final String LISTING_MODE = "phoneNumberPrivacy.listingMode";
public static final String LISTING_TIMESTAMP = "phoneNumberPrivacy.listingMode.timestamp";
public static final String USERNAME_OUT_OF_SYNC = "phoneNumberPrivacy.usernameOutOfSync";
public static final String SHARING_MODE = "phoneNumberPrivacy.sharingMode";
public static final String LISTING_MODE = "phoneNumberPrivacy.listingMode";
public static final String LISTING_TIMESTAMP = "phoneNumberPrivacy.listingMode.timestamp";
private static final Collection<CertificateType> REGULAR_CERTIFICATE = Collections.singletonList(CertificateType.UUID_AND_E164);
private static final Collection<CertificateType> PRIVACY_CERTIFICATE = Collections.singletonList(CertificateType.UUID_ONLY);
@@ -69,18 +68,6 @@ public final class PhoneNumberPrivacyValues extends SignalStoreValues {
return getLong(LISTING_TIMESTAMP, 0);
}
public void markUsernameOutOfSync() {
putBoolean(USERNAME_OUT_OF_SYNC, true);
}
public void clearUsernameOutOfSync() {
putBoolean(USERNAME_OUT_OF_SYNC, false);
}
public boolean isUsernameOutOfSync() {
return getBoolean(USERNAME_OUT_OF_SYNC, false);
}
/**
* If you respect {@link #getPhoneNumberSharingMode}, then you will only ever need to fetch and store
* these certificates types.