mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-02 08:23:00 +01:00
Replace usages of old getEncryptedUsernameFromLinkServerId for libsignal's lookUpUsernameLink.
This commit is contained in:
committed by
Cody Henthorne
parent
caf2e555dd
commit
402f49edd9
@@ -4,6 +4,7 @@ import android.text.TextUtils
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.Util
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.libsignal.net.RequestResult
|
||||
import org.signal.libsignal.usernames.BaseUsernameException
|
||||
import org.signal.libsignal.usernames.Username
|
||||
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential
|
||||
@@ -26,7 +27,6 @@ import org.thoughtcrime.securesms.profiles.manage.UsernameRepository
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.ProfileUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.NetworkResultUtil
|
||||
import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher
|
||||
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential
|
||||
@@ -384,9 +384,7 @@ class RefreshOwnProfileJob private constructor(parameters: Parameters) : BaseJob
|
||||
val displayBadgesOnProfile = SignalStore.inAppPayments.getDisplayBadgesOnProfile()
|
||||
Log.d(
|
||||
TAG,
|
||||
"Detected mixed visibility of badges. Telling the server to mark them all " +
|
||||
(if (displayBadgesOnProfile) "" else "not") +
|
||||
" visible.",
|
||||
"Detected mixed visibility of badges. Telling the server to mark them all ${if (displayBadgesOnProfile) "" else "not"} visible.",
|
||||
true
|
||||
)
|
||||
|
||||
@@ -399,8 +397,6 @@ class RefreshOwnProfileJob private constructor(parameters: Parameters) : BaseJob
|
||||
}
|
||||
|
||||
private fun checkUsernameIsInSync() {
|
||||
var validated = false
|
||||
|
||||
try {
|
||||
val localUsername = SignalStore.account.username
|
||||
|
||||
@@ -429,32 +425,37 @@ class RefreshOwnProfileJob private constructor(parameters: Parameters) : BaseJob
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val localUsernameLink = SignalStore.account.usernameLink
|
||||
val localUsernameLink = SignalStore.account.usernameLink ?: return
|
||||
|
||||
if (localUsernameLink != null) {
|
||||
val remoteEncryptedUsername = NetworkResultUtil.toBasicLegacy<ByteArray>(SignalNetwork.username.getEncryptedUsernameFromLinkServerId(localUsernameLink.serverId))
|
||||
val combinedLink = Username.UsernameLink(localUsernameLink.entropy, remoteEncryptedUsername)
|
||||
val remoteUsername = Username.fromLink(combinedLink)
|
||||
when (val usernameFetchResult = SignalNetwork.username.getDecryptedUsernameFromLinkServerIdAndEntropy(localUsernameLink.serverId, localUsernameLink.entropy)) {
|
||||
is RequestResult.Success -> {
|
||||
val remoteUsername = usernameFetchResult.result
|
||||
|
||||
if (remoteUsername == null) {
|
||||
Log.w(TAG, "Local username link was not found on remote. Marking as mismatched.")
|
||||
UsernameRepository.onUsernameLinkMismatchDetected()
|
||||
return
|
||||
}
|
||||
|
||||
if (remoteUsername.getUsername() != SignalStore.account.username) {
|
||||
Log.w(TAG, "The remote username decrypted ok, but the decrypted username did not match our local username!")
|
||||
UsernameRepository.onUsernameLinkMismatchDetected()
|
||||
} else {
|
||||
Log.d(TAG, "Username link validated.")
|
||||
return
|
||||
}
|
||||
|
||||
validated = true
|
||||
Log.d(TAG, "Username link validated.")
|
||||
UsernameRepository.onUsernameConsistencyValidated()
|
||||
}
|
||||
is RequestResult.NonSuccess -> {
|
||||
Log.w(TAG, "Failed to decrypt username link using our local link data. ${usernameFetchResult.error}")
|
||||
UsernameRepository.onUsernameLinkMismatchDetected()
|
||||
}
|
||||
is RequestResult.RetryableNetworkError -> {
|
||||
Log.w(TAG, "Failed perform synchronization check during the username link phase, skipping.", usernameFetchResult.networkError)
|
||||
}
|
||||
is RequestResult.ApplicationError -> {
|
||||
throw usernameFetchResult.cause
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Failed perform synchronization check during the username link phase.", e)
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "Failed to decrypt username link using the remote encrypted username and our local entropy!", e)
|
||||
UsernameRepository.onUsernameLinkMismatchDetected()
|
||||
}
|
||||
|
||||
if (validated) {
|
||||
UsernameRepository.onUsernameConsistencyValidated()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import org.signal.core.util.toByteArray
|
||||
import org.signal.libsignal.net.RequestResult
|
||||
import org.signal.libsignal.usernames.BaseUsernameException
|
||||
import org.signal.libsignal.usernames.Username
|
||||
import org.signal.libsignal.usernames.UsernameLinkInvalidEntropyDataLength
|
||||
import org.signal.libsignal.usernames.UsernameLinkInvalidLinkData
|
||||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameLinkResetResult
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
@@ -234,25 +236,24 @@ object UsernameRepository {
|
||||
|
||||
return Single
|
||||
.fromCallable {
|
||||
val encryptedUsername = when (val result = SignalNetwork.username.getEncryptedUsernameFromLinkServerId(components.serverId)) {
|
||||
is NetworkResult.Success -> result.result
|
||||
is NetworkResult.StatusCodeError -> {
|
||||
return@fromCallable when (result.code) {
|
||||
404 -> UsernameLinkConversionResult.NotFound(null)
|
||||
422 -> UsernameLinkConversionResult.Invalid
|
||||
else -> UsernameLinkConversionResult.NetworkError
|
||||
val username = when (val result = SignalNetwork.username.getDecryptedUsernameFromLinkServerIdAndEntropy(components.serverId, components.entropy)) {
|
||||
is RequestResult.Success ->
|
||||
result.result ?: return@fromCallable UsernameLinkConversionResult.NotFound(null)
|
||||
is RequestResult.NonSuccess -> {
|
||||
when (result.error) {
|
||||
is UsernameLinkInvalidEntropyDataLength,
|
||||
is UsernameLinkInvalidLinkData -> {
|
||||
Log.w(TAG, "[convertLinkToUsername] Bad username conversion. ${result.error}")
|
||||
return@fromCallable UsernameLinkConversionResult.Invalid
|
||||
}
|
||||
}
|
||||
}
|
||||
is NetworkResult.NetworkError -> return@fromCallable UsernameLinkConversionResult.NetworkError
|
||||
is NetworkResult.ApplicationError -> throw result.throwable
|
||||
}
|
||||
|
||||
val link = Username.UsernameLink(components.entropy, encryptedUsername)
|
||||
val username: Username = try {
|
||||
Username.fromLink(link)
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "[convertLinkToUsername] Bad username conversion.", e)
|
||||
return@fromCallable UsernameLinkConversionResult.Invalid
|
||||
is RequestResult.RetryableNetworkError -> {
|
||||
return@fromCallable UsernameLinkConversionResult.NetworkError
|
||||
}
|
||||
is RequestResult.ApplicationError -> {
|
||||
throw result.cause
|
||||
}
|
||||
}
|
||||
|
||||
when (val result = SignalNetwork.username.getAciByUsername(username)) {
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.whispersystems.signalservice.api.username
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.signal.core.models.ServiceId
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.libsignal.net.LookUpUsernameLinkFailure
|
||||
import org.signal.libsignal.net.RequestResult
|
||||
import org.signal.libsignal.net.UnauthUsernamesService
|
||||
import org.signal.libsignal.net.getOrError
|
||||
@@ -27,7 +28,10 @@ import java.util.UUID
|
||||
class UsernameApi(private val unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket) {
|
||||
|
||||
/**
|
||||
* Gets the ACI for the given [username], if it exists. This is an unauthenticated request.
|
||||
* Gets the ACI for the given [username]. This is an unauthenticated request.
|
||||
*
|
||||
* A successful result with a null value means the username was not found on the server.
|
||||
* Other errors (network, decryption, etc.) are represented by the other [RequestResult] types.
|
||||
*/
|
||||
fun getAciByUsername(username: Username): RequestResult<ServiceId.ACI?, Nothing> {
|
||||
return runBlocking {
|
||||
@@ -38,18 +42,16 @@ class UsernameApi(private val unauthWebSocket: SignalWebSocket.UnauthenticatedWe
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a link serverId, this will return the encrypted username associated with the link.
|
||||
* Gets the username for a ([serverId], [entropy]) pairing from a username link. This is an unauthenticated request.
|
||||
*
|
||||
* GET /v1/accounts/username_hash/[serverId]
|
||||
* - 200: Success
|
||||
* - 400: Request must not be authenticated
|
||||
* - 404: Username link not found for server id
|
||||
* - 422: Invalid request format
|
||||
* - 429: Rate limited
|
||||
* A successful result with a null value means no username link was found for the given server ID.
|
||||
* Other errors (network, decryption, etc.) are represented by the other [RequestResult] types.
|
||||
*/
|
||||
fun getEncryptedUsernameFromLinkServerId(serverId: UUID): NetworkResult<ByteArray> {
|
||||
val request = WebSocketRequestMessage.get("/v1/accounts/username_link/$serverId")
|
||||
return NetworkResult.fromWebSocketRequest(unauthWebSocket, request, GetUsernameFromLinkResponseBody::class)
|
||||
.map { Base64.decode(it.usernameLinkEncryptedValue) }
|
||||
fun getDecryptedUsernameFromLinkServerIdAndEntropy(serverId: UUID, entropy: ByteArray): RequestResult<Username?, LookUpUsernameLinkFailure> {
|
||||
return runBlocking {
|
||||
unauthWebSocket.runCatchingWithUnauthChatConnection { chatConnection ->
|
||||
UnauthUsernamesService(chatConnection).lookUpUsernameLink(serverId, entropy)
|
||||
}.getOrError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user