mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-03-02 23:38:34 +00:00
Convert all account based calls to WebSocket.
This commit is contained in:
committed by
Greyson Parrelli
parent
6d115a912d
commit
305b380fef
@@ -47,7 +47,6 @@ import androidx.transition.TransitionManager;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.signal.core.util.concurrent.JvmRxExtensions;
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.signal.core.util.logging.Log;
|
||||
@@ -721,12 +720,7 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
AlertDialog loadingDialog = SimpleProgressDialog.show(requireContext());
|
||||
|
||||
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
|
||||
try {
|
||||
return JvmRxExtensions.safeBlockingGet(UsernameRepository.fetchAciForUsername(UsernameUtil.sanitizeUsernameFromSearch(username)));
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(TAG, "Interrupted?", e);
|
||||
return UsernameAciFetchResult.NetworkError.INSTANCE;
|
||||
}
|
||||
return UsernameRepository.fetchAciForUsername(UsernameUtil.sanitizeUsernameFromSearch(username));
|
||||
}, result -> {
|
||||
loadingDialog.dismiss();
|
||||
|
||||
|
||||
@@ -5,22 +5,22 @@ import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager
|
||||
import java.io.IOException
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
|
||||
class ExportAccountDataRepository(
|
||||
private val accountManager: SignalServiceAccountManager = AppDependencies.signalServiceAccountManager
|
||||
) {
|
||||
class ExportAccountDataRepository {
|
||||
|
||||
fun downloadAccountDataReport(exportAsJson: Boolean): Single<ExportedReport> {
|
||||
return Single.create {
|
||||
try {
|
||||
it.onSuccess(generateAccountDataReport(accountManager.accountDataReport, exportAsJson))
|
||||
} catch (e: IOException) {
|
||||
it.onError(e)
|
||||
when (val result = SignalNetwork.account.accountDataReport()) {
|
||||
is NetworkResult.Success -> {
|
||||
it.onSuccess(generateAccountDataReport(result.result, exportAsJson))
|
||||
}
|
||||
else -> {
|
||||
it.onError(result.getCause()!!)
|
||||
}
|
||||
}
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob
|
||||
import org.thoughtcrime.securesms.keyvalue.CertificateType
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.pin.SvrRepository
|
||||
import org.thoughtcrime.securesms.pin.SvrWrongPinException
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
@@ -266,7 +267,7 @@ class ChangeNumberRepository(
|
||||
|
||||
SignalStore.misc.setPendingChangeNumberMetadata(metadata)
|
||||
withContext(Dispatchers.IO) {
|
||||
result = accountManager.registrationApi.changeNumber(request)
|
||||
result = SignalNetwork.account.changeNumber(request)
|
||||
}
|
||||
|
||||
val possibleError = result.getCause() as? MismatchedDevicesException
|
||||
|
||||
@@ -9,12 +9,13 @@ import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.NetworkResultUtil
|
||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException
|
||||
import java.io.IOException
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
private val TAG = Log.tag(AdvancedPrivacySettingsRepository::class.java)
|
||||
@@ -24,9 +25,8 @@ class AdvancedPrivacySettingsRepository(private val context: Context) {
|
||||
fun disablePushMessages(consumer: (DisablePushMessagesResult) -> Unit) {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
val result = try {
|
||||
val accountManager = AppDependencies.signalServiceAccountManager
|
||||
try {
|
||||
accountManager.setGcmId(Optional.empty())
|
||||
NetworkResultUtil.toBasicLegacy(SignalNetwork.account.clearFcmToken())
|
||||
} catch (e: AuthorizationFailedException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.whispersystems.signalservice.api.NetworkResultUtil;
|
||||
import org.whispersystems.signalservice.internal.EmptyResponse;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
|
||||
@@ -103,7 +105,7 @@ class DeleteAccountRepository {
|
||||
Log.i(TAG, "deleteAccount: attempting to delete account from server...");
|
||||
|
||||
try {
|
||||
AppDependencies.getSignalServiceAccountManager().deleteAccount();
|
||||
NetworkResultUtil.toBasicLegacy(SignalNetwork.account().deleteAccount());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "deleteAccount: failed to delete account from signal service", e);
|
||||
onDeleteAccountEvent.accept(DeleteAccountEvent.ServerDeletionFailed.INSTANCE);
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager
|
||||
import org.whispersystems.signalservice.api.SignalServiceDataStore
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender
|
||||
import org.whispersystems.signalservice.api.account.AccountApi
|
||||
import org.whispersystems.signalservice.api.archive.ArchiveApi
|
||||
import org.whispersystems.signalservice.api.attachment.AttachmentApi
|
||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
|
||||
@@ -52,6 +53,7 @@ import org.whispersystems.signalservice.api.services.CallLinksService
|
||||
import org.whispersystems.signalservice.api.services.DonationsService
|
||||
import org.whispersystems.signalservice.api.services.ProfileService
|
||||
import org.whispersystems.signalservice.api.storage.StorageServiceApi
|
||||
import org.whispersystems.signalservice.api.username.UsernameApi
|
||||
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
|
||||
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration
|
||||
@@ -311,6 +313,12 @@ object AppDependencies {
|
||||
val storageServiceApi: StorageServiceApi
|
||||
get() = networkModule.storageServiceApi
|
||||
|
||||
val accountApi: AccountApi
|
||||
get() = networkModule.accountApi
|
||||
|
||||
val usernameApi: UsernameApi
|
||||
get() = networkModule.usernameApi
|
||||
|
||||
@JvmStatic
|
||||
val okHttpClient: OkHttpClient
|
||||
get() = networkModule.okHttpClient
|
||||
@@ -338,7 +346,7 @@ object AppDependencies {
|
||||
interface Provider {
|
||||
fun providePushServiceSocket(signalServiceConfiguration: SignalServiceConfiguration, groupsV2Operations: GroupsV2Operations): PushServiceSocket
|
||||
fun provideGroupsV2Operations(signalServiceConfiguration: SignalServiceConfiguration): GroupsV2Operations
|
||||
fun provideSignalServiceAccountManager(pushServiceSocket: PushServiceSocket, groupsV2Operations: GroupsV2Operations): SignalServiceAccountManager
|
||||
fun provideSignalServiceAccountManager(authWebSocket: AccountApi, pushServiceSocket: PushServiceSocket, groupsV2Operations: GroupsV2Operations): SignalServiceAccountManager
|
||||
fun provideSignalServiceMessageSender(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket, protocolStore: SignalServiceDataStore, pushServiceSocket: PushServiceSocket): SignalServiceMessageSender
|
||||
fun provideSignalServiceMessageReceiver(pushServiceSocket: PushServiceSocket): SignalServiceMessageReceiver
|
||||
fun provideSignalServiceNetworkAccess(): SignalServiceNetworkAccess
|
||||
@@ -382,5 +390,7 @@ object AppDependencies {
|
||||
fun provideStorageServiceApi(pushServiceSocket: PushServiceSocket): StorageServiceApi
|
||||
fun provideAuthWebSocket(signalServiceConfigurationSupplier: Supplier<SignalServiceConfiguration>, libSignalNetworkSupplier: Supplier<Network>): SignalWebSocket.AuthenticatedWebSocket
|
||||
fun provideUnauthWebSocket(signalServiceConfigurationSupplier: Supplier<SignalServiceConfiguration>, libSignalNetworkSupplier: Supplier<Network>): SignalWebSocket.UnauthenticatedWebSocket
|
||||
fun provideAccountApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): AccountApi
|
||||
fun provideUsernameApi(unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): UsernameApi
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.SignalServiceDataStore;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.account.AccountApi;
|
||||
import org.whispersystems.signalservice.api.archive.ArchiveApi;
|
||||
import org.whispersystems.signalservice.api.attachment.AttachmentApi;
|
||||
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
|
||||
@@ -93,6 +94,7 @@ import org.whispersystems.signalservice.api.services.CallLinksService;
|
||||
import org.whispersystems.signalservice.api.services.DonationsService;
|
||||
import org.whispersystems.signalservice.api.services.ProfileService;
|
||||
import org.whispersystems.signalservice.api.storage.StorageServiceApi;
|
||||
import org.whispersystems.signalservice.api.username.UsernameApi;
|
||||
import org.whispersystems.signalservice.api.util.CredentialsProvider;
|
||||
import org.whispersystems.signalservice.api.util.SleepTimer;
|
||||
import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
|
||||
@@ -140,8 +142,8 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SignalServiceAccountManager provideSignalServiceAccountManager(@NonNull PushServiceSocket pushServiceSocket, @NonNull GroupsV2Operations groupsV2Operations) {
|
||||
return new SignalServiceAccountManager(pushServiceSocket, groupsV2Operations);
|
||||
public @NonNull SignalServiceAccountManager provideSignalServiceAccountManager(@NonNull AccountApi accountApi, @NonNull PushServiceSocket pushServiceSocket, @NonNull GroupsV2Operations groupsV2Operations) {
|
||||
return new SignalServiceAccountManager(accountApi, pushServiceSocket, groupsV2Operations);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -492,6 +494,16 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
|
||||
return new StorageServiceApi(pushServiceSocket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull AccountApi provideAccountApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket) {
|
||||
return new AccountApi(authWebSocket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull UsernameApi provideUsernameApi(@NonNull SignalWebSocket.UnauthenticatedWebSocket unauthWebSocket) {
|
||||
return new UsernameApi(unauthWebSocket);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class DynamicCredentialsProvider implements CredentialsProvider {
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.push.SignalServiceTrustStore
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender
|
||||
import org.whispersystems.signalservice.api.account.AccountApi
|
||||
import org.whispersystems.signalservice.api.archive.ArchiveApi
|
||||
import org.whispersystems.signalservice.api.attachment.AttachmentApi
|
||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
|
||||
@@ -37,6 +38,7 @@ import org.whispersystems.signalservice.api.services.CallLinksService
|
||||
import org.whispersystems.signalservice.api.services.DonationsService
|
||||
import org.whispersystems.signalservice.api.services.ProfileService
|
||||
import org.whispersystems.signalservice.api.storage.StorageServiceApi
|
||||
import org.whispersystems.signalservice.api.username.UsernameApi
|
||||
import org.whispersystems.signalservice.api.util.Tls12SocketFactory
|
||||
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
|
||||
@@ -83,7 +85,7 @@ class NetworkDependenciesModule(
|
||||
}
|
||||
|
||||
val signalServiceAccountManager: SignalServiceAccountManager by lazy {
|
||||
provider.provideSignalServiceAccountManager(pushServiceSocket, groupsV2Operations)
|
||||
provider.provideSignalServiceAccountManager(accountApi, pushServiceSocket, groupsV2Operations)
|
||||
}
|
||||
|
||||
val libsignalNetwork: Network by lazy {
|
||||
@@ -157,6 +159,14 @@ class NetworkDependenciesModule(
|
||||
provider.provideStorageServiceApi(pushServiceSocket)
|
||||
}
|
||||
|
||||
val accountApi: AccountApi by lazy {
|
||||
provider.provideAccountApi(authWebSocket)
|
||||
}
|
||||
|
||||
val usernameApi: UsernameApi by lazy {
|
||||
provider.provideUsernameApi(unauthWebSocket)
|
||||
}
|
||||
|
||||
val okHttpClient: OkHttpClient by lazy {
|
||||
OkHttpClient.Builder()
|
||||
.addInterceptor(StandardUserAgentInterceptor())
|
||||
|
||||
@@ -38,9 +38,11 @@ import org.thoughtcrime.securesms.gcm.FcmUtil;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationIds;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.whispersystems.signalservice.api.NetworkResultUtil;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -100,7 +102,7 @@ public class FcmRefreshJob extends BaseJob {
|
||||
Log.i(TAG, "Token didn't change.");
|
||||
}
|
||||
|
||||
AppDependencies.getSignalServiceAccountManager().setGcmId(token);
|
||||
NetworkResultUtil.toBasicLegacy(SignalNetwork.account().setFcmToken(token.get()));
|
||||
SignalStore.account().setFcmToken(token.get());
|
||||
} else {
|
||||
throw new RetryLaterException(new IOException("Failed to retrieve a token."));
|
||||
|
||||
@@ -19,15 +19,16 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
import org.whispersystems.signalservice.api.account.PniKeyDistributionRequest
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity
|
||||
import org.whispersystems.signalservice.internal.push.KyberPreKeyEntity
|
||||
import org.whispersystems.signalservice.internal.push.MismatchedDevices
|
||||
import org.whispersystems.signalservice.internal.push.OutgoingPushMessage
|
||||
import org.whispersystems.signalservice.internal.push.SyncMessage
|
||||
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse
|
||||
import org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException
|
||||
import java.io.IOException
|
||||
import java.security.SecureRandom
|
||||
|
||||
@@ -112,7 +113,6 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base
|
||||
}
|
||||
|
||||
private fun initializeDevices(newE164: String): Single<NetworkResult<VerifyAccountResponse>> {
|
||||
val accountManager = AppDependencies.signalServiceAccountManager
|
||||
val messageSender = AppDependencies.signalServiceMessageSender
|
||||
|
||||
return Single.fromCallable {
|
||||
@@ -125,15 +125,25 @@ class PnpInitializeDevicesJob private constructor(parameters: Parameters) : Base
|
||||
newE164 = newE164
|
||||
)
|
||||
|
||||
distributionResponse = accountManager.registrationApi.distributePniKeys(request)
|
||||
|
||||
if (distributionResponse is NetworkResult.StatusCodeError &&
|
||||
distributionResponse.exception is MismatchedDevicesException
|
||||
) {
|
||||
messageSender.handleChangeNumberMismatchDevices((distributionResponse.exception as MismatchedDevicesException).mismatchedDevices)
|
||||
attempts++
|
||||
} else {
|
||||
completed = true
|
||||
distributionResponse = SignalNetwork.account.distributePniKeys(request)
|
||||
when (val result = distributionResponse) {
|
||||
is NetworkResult.Success -> completed = true
|
||||
is NetworkResult.StatusCodeError -> {
|
||||
when (result.code) {
|
||||
409 -> {
|
||||
val mismatchedDevices: MismatchedDevices? = result.parseJsonBody()
|
||||
if (mismatchedDevices != null) {
|
||||
messageSender.handleChangeNumberMismatchDevices(mismatchedDevices)
|
||||
} else {
|
||||
Log.w(TAG, "Unable to parse mismatched devices", result.exception)
|
||||
}
|
||||
attempts++
|
||||
}
|
||||
else -> completed = true
|
||||
}
|
||||
}
|
||||
is NetworkResult.NetworkError -> attempts++
|
||||
is NetworkResult.ApplicationError -> completed = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,12 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.keyvalue.SvrValues;
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork;
|
||||
import org.thoughtcrime.securesms.registration.data.RegistrationRepository;
|
||||
import org.thoughtcrime.securesms.registration.secondary.DeviceNameCipher;
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.NetworkResultUtil;
|
||||
import org.whispersystems.signalservice.api.account.AccountAttributes;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NetworkFailureException;
|
||||
@@ -125,7 +127,7 @@ public class RefreshAttributesJob extends BaseJob {
|
||||
recoveryPassword
|
||||
);
|
||||
|
||||
AppDependencies.getSignalServiceAccountManager().setAccountAttributes(accountAttributes);
|
||||
NetworkResultUtil.toBasicLegacy(SignalNetwork.account().setAccountAttributes(accountAttributes));
|
||||
|
||||
hasRefreshedThisAppCycle = true;
|
||||
}
|
||||
|
||||
@@ -23,12 +23,14 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
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.thoughtcrime.securesms.util.Util;
|
||||
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;
|
||||
@@ -328,7 +330,7 @@ public class RefreshOwnProfileJob extends BaseJob {
|
||||
UsernameLinkComponents localUsernameLink = SignalStore.account().getUsernameLink();
|
||||
|
||||
if (localUsernameLink != null) {
|
||||
byte[] remoteEncryptedUsername = AppDependencies.getSignalServiceAccountManager().getEncryptedUsernameFromLinkServerId(localUsernameLink.getServerId());
|
||||
byte[] remoteEncryptedUsername = NetworkResultUtil.toBasicLegacy(SignalNetwork.username().getEncryptedUsernameFromLinkServerId(localUsernameLink.getServerId()));
|
||||
Username.UsernameLink combinedLink = new Username.UsernameLink(localUsernameLink.getEntropy(), remoteEncryptedUsername);
|
||||
Username remoteUsername = Username.fromLink(combinedLink);
|
||||
|
||||
|
||||
@@ -6,16 +6,23 @@
|
||||
package org.thoughtcrime.securesms.net
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.whispersystems.signalservice.api.account.AccountApi
|
||||
import org.whispersystems.signalservice.api.archive.ArchiveApi
|
||||
import org.whispersystems.signalservice.api.attachment.AttachmentApi
|
||||
import org.whispersystems.signalservice.api.keys.KeysApi
|
||||
import org.whispersystems.signalservice.api.link.LinkDeviceApi
|
||||
import org.whispersystems.signalservice.api.storage.StorageServiceApi
|
||||
import org.whispersystems.signalservice.api.username.UsernameApi
|
||||
|
||||
/**
|
||||
* A convenient way to access network operations, similar to [org.thoughtcrime.securesms.database.SignalDatabase] and [org.thoughtcrime.securesms.keyvalue.SignalStore].
|
||||
*/
|
||||
object SignalNetwork {
|
||||
@JvmStatic
|
||||
@get:JvmName("account")
|
||||
val account: AccountApi
|
||||
get() = AppDependencies.accountApi
|
||||
|
||||
val archive: ArchiveApi
|
||||
get() = AppDependencies.archiveApi
|
||||
|
||||
@@ -30,4 +37,9 @@ object SignalNetwork {
|
||||
|
||||
val storageService: StorageServiceApi
|
||||
get() = AppDependencies.storageServiceApi
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("username")
|
||||
val username: UsernameApi
|
||||
get() = AppDependencies.usernameApi
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ import org.thoughtcrime.securesms.jobs.Svr3MirrorJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.registration.viewmodel.SvrAuthCredentialSet
|
||||
import org.thoughtcrime.securesms.registrationv3.ui.restore.StorageServiceRestore
|
||||
import org.whispersystems.signalservice.api.NetworkResultUtil
|
||||
import org.whispersystems.signalservice.api.SvrNoDataException
|
||||
import org.whispersystems.signalservice.api.kbs.MasterKey
|
||||
import org.whispersystems.signalservice.api.svr.SecureValueRecovery
|
||||
@@ -360,7 +362,7 @@ object SvrRepository {
|
||||
check(SignalStore.svr.hasOptedInWithAccess() && !SignalStore.svr.hasOptedOut()) { "Must have a PIN to set a registration lock!" }
|
||||
|
||||
Log.i(TAG, "[enableRegistrationLockForUserWithPin] Enabling registration lock.", true)
|
||||
AppDependencies.signalServiceAccountManager.enableRegistrationLock(SignalStore.svr.masterKey)
|
||||
NetworkResultUtil.toBasicLegacy(SignalNetwork.account.enableRegistrationLock(SignalStore.svr.masterKey.deriveRegistrationLock()))
|
||||
SignalStore.svr.isRegistrationLockEnabled = true
|
||||
Log.i(TAG, "[enableRegistrationLockForUserWithPin] Registration lock successfully enabled.", true)
|
||||
}
|
||||
@@ -374,7 +376,7 @@ object SvrRepository {
|
||||
check(SignalStore.svr.hasOptedInWithAccess() && !SignalStore.svr.hasOptedOut()) { "Must have a PIN to disable registration lock!" }
|
||||
|
||||
Log.i(TAG, "[disableRegistrationLockForUserWithPin] Disabling registration lock.", true)
|
||||
AppDependencies.signalServiceAccountManager.disableRegistrationLock()
|
||||
NetworkResultUtil.toBasicLegacy(SignalNetwork.account.disableRegistrationLock())
|
||||
SignalStore.svr.isRegistrationLockEnabled = false
|
||||
Log.i(TAG, "[disableRegistrationLockForUserWithPin] Registration lock successfully disabled.", true)
|
||||
}
|
||||
|
||||
@@ -15,23 +15,18 @@ import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.AccountValues
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.NetworkUtil
|
||||
import org.thoughtcrime.securesms.util.UsernameUtil
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.api.push.UsernameLinkComponents
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException
|
||||
import org.whispersystems.signalservice.api.push.exceptions.RateLimitException
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UsernameIsNotAssociatedWithAnAccountException
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UsernameIsNotReservedException
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UsernameMalformedException
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UsernameTakenException
|
||||
import org.whispersystems.signalservice.api.util.Usernames
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil
|
||||
import org.whispersystems.signalservice.api.util.toByteArray
|
||||
import java.io.IOException
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
@@ -200,26 +195,30 @@ object UsernameRepository {
|
||||
|
||||
return Single
|
||||
.fromCallable {
|
||||
try {
|
||||
SignalStore.account.usernameLink = null
|
||||
SignalStore.account.usernameLink = null
|
||||
|
||||
Log.d(TAG, "[createOrResetUsernameLink] Creating username link...")
|
||||
val components = accountManager.createUsernameLink(username)
|
||||
SignalStore.account.usernameLink = components
|
||||
Log.d(TAG, "[createOrResetUsernameLink] Creating username link...")
|
||||
|
||||
if (SignalStore.account.usernameSyncState == AccountValues.UsernameSyncState.LINK_CORRUPTED) {
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
val usernameLink = username.generateLink()
|
||||
when (val result = SignalNetwork.account.createUsernameLink(usernameLink)) {
|
||||
is NetworkResult.Success -> {
|
||||
SignalStore.account.usernameLink = result.result
|
||||
|
||||
if (SignalStore.account.usernameSyncState == AccountValues.UsernameSyncState.LINK_CORRUPTED) {
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
}
|
||||
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.d(TAG, "[createOrResetUsernameLink] Username link created.")
|
||||
|
||||
UsernameLinkResetResult.Success(result.result)
|
||||
}
|
||||
else -> {
|
||||
Log.w(TAG, "[createOrResetUsernameLink] Failed to rotate the username!", result.getCause())
|
||||
UsernameLinkResetResult.NetworkError
|
||||
}
|
||||
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.d(TAG, "[createOrResetUsernameLink] Username link created.")
|
||||
|
||||
UsernameLinkResetResult.Success(components)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[createOrResetUsernameLink] Failed to rotate the username!", e)
|
||||
UsernameLinkResetResult.NetworkError
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
@@ -234,53 +233,72 @@ object UsernameRepository {
|
||||
|
||||
return Single
|
||||
.fromCallable {
|
||||
var username: Username? = null
|
||||
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
|
||||
}
|
||||
}
|
||||
is NetworkResult.NetworkError -> return@fromCallable UsernameLinkConversionResult.NetworkError
|
||||
is NetworkResult.ApplicationError -> throw result.throwable
|
||||
}
|
||||
|
||||
try {
|
||||
val encryptedUsername: ByteArray = accountManager.getEncryptedUsernameFromLinkServerId(components.serverId)
|
||||
val link = Username.UsernameLink(components.entropy, encryptedUsername)
|
||||
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
|
||||
}
|
||||
|
||||
username = Username.fromLink(link)
|
||||
|
||||
val aci = accountManager.getAciByUsername(username)
|
||||
|
||||
UsernameLinkConversionResult.Success(username, aci)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[convertLinkToUsername] Failed to lookup user.", e)
|
||||
|
||||
if (e is NonSuccessfulResponseCodeException) {
|
||||
when (e.code) {
|
||||
when (val result = SignalNetwork.username.getAciByUsername(username)) {
|
||||
is NetworkResult.Success -> UsernameLinkConversionResult.Success(username, result.result)
|
||||
is NetworkResult.StatusCodeError -> {
|
||||
Log.w(TAG, "[convertLinkToUsername] Failed to lookup user.", result.exception)
|
||||
when (result.code) {
|
||||
404 -> UsernameLinkConversionResult.NotFound(username)
|
||||
422 -> UsernameLinkConversionResult.Invalid
|
||||
else -> UsernameLinkConversionResult.NetworkError
|
||||
}
|
||||
} else {
|
||||
}
|
||||
is NetworkResult.NetworkError -> {
|
||||
Log.w(TAG, "[convertLinkToUsername] Failed to lookup user.", result.exception)
|
||||
UsernameLinkConversionResult.NetworkError
|
||||
}
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "[convertLinkToUsername] Bad username conversion.", e)
|
||||
UsernameLinkConversionResult.Invalid
|
||||
is NetworkResult.ApplicationError -> throw result.throwable
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fetchAciForUsername(username: String): Single<UsernameAciFetchResult> {
|
||||
return Single.fromCallable {
|
||||
try {
|
||||
val aci: ACI = AppDependencies.signalServiceAccountManager.getAciByUsername(Username(username))
|
||||
UsernameAciFetchResult.Success(aci)
|
||||
} catch (e: UsernameIsNotAssociatedWithAnAccountException) {
|
||||
Log.w(TAG, "[fetchAciFromUsername] Failed to get ACI for username hash", e)
|
||||
UsernameAciFetchResult.NotFound
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "[fetchAciFromUsername] Invalid username", e)
|
||||
UsernameAciFetchResult.NotFound
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[fetchAciFromUsername] Hit network error while trying to resolve ACI from username", e)
|
||||
fun fetchAciForUsername(usernameString: String): UsernameAciFetchResult {
|
||||
val username = try {
|
||||
Username(usernameString)
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "[fetchAciFromUsername] Invalid username", e)
|
||||
return UsernameAciFetchResult.NotFound
|
||||
}
|
||||
|
||||
return when (val result = SignalNetwork.username.getAciByUsername(username)) {
|
||||
is NetworkResult.Success -> UsernameAciFetchResult.Success(result.result)
|
||||
is NetworkResult.StatusCodeError -> {
|
||||
Log.w(TAG, "[fetchAciFromUsername] Failed to get ACI for username hash", result.exception)
|
||||
when (result.code) {
|
||||
404 -> UsernameAciFetchResult.NotFound
|
||||
else -> UsernameAciFetchResult.NetworkError
|
||||
}
|
||||
}
|
||||
|
||||
is NetworkResult.NetworkError -> {
|
||||
Log.w(TAG, "[fetchAciFromUsername] Hit network error while trying to resolve ACI from username", result.exception)
|
||||
UsernameAciFetchResult.NetworkError
|
||||
}
|
||||
|
||||
is NetworkResult.ApplicationError -> throw result.throwable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,41 +373,56 @@ object UsernameRepository {
|
||||
|
||||
@WorkerThread
|
||||
private fun reserveUsernameInternal(nickname: String, discriminator: String?): Result<UsernameState.Reserved, UsernameSetResult> {
|
||||
return try {
|
||||
val candidates: List<Username> = if (discriminator == null) {
|
||||
val candidates: List<Username> = try {
|
||||
if (discriminator == null) {
|
||||
Username.candidatesFrom(nickname, UsernameUtil.MIN_NICKNAME_LENGTH, UsernameUtil.MAX_NICKNAME_LENGTH)
|
||||
} else {
|
||||
listOf(Username("$nickname${Usernames.DELIMITER}$discriminator"))
|
||||
}
|
||||
|
||||
val hashes: List<String> = candidates
|
||||
.map { Base64.encodeUrlSafeWithoutPadding(it.hash) }
|
||||
|
||||
val response = accountManager.reserveUsername(hashes)
|
||||
|
||||
val hashIndex = hashes.indexOf(response.usernameHash)
|
||||
if (hashIndex == -1) {
|
||||
Log.w(TAG, "[reserveUsername] The response hash could not be found in our set of hashes.")
|
||||
return failure(UsernameSetResult.CANDIDATE_GENERATION_ERROR)
|
||||
}
|
||||
|
||||
Log.i(TAG, "[reserveUsername] Successfully reserved username.")
|
||||
success(UsernameState.Reserved(candidates[hashIndex]))
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "[reserveUsername] An error occurred while generating candidates.")
|
||||
failure(UsernameSetResult.CANDIDATE_GENERATION_ERROR)
|
||||
} catch (e: UsernameTakenException) {
|
||||
Log.w(TAG, "[reserveUsername] Username taken.")
|
||||
failure(UsernameSetResult.USERNAME_UNAVAILABLE)
|
||||
} catch (e: UsernameMalformedException) {
|
||||
Log.w(TAG, "[reserveUsername] Username malformed.")
|
||||
failure(UsernameSetResult.USERNAME_INVALID)
|
||||
} catch (e: RateLimitException) {
|
||||
Log.w(TAG, "[reserveUsername] Rate limit exceeded.")
|
||||
failure(UsernameSetResult.RATE_LIMIT_ERROR)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[reserveUsername] Generic network exception.", e)
|
||||
failure(UsernameSetResult.NETWORK_ERROR)
|
||||
return failure(UsernameSetResult.CANDIDATE_GENERATION_ERROR)
|
||||
}
|
||||
|
||||
val hashes: List<String> = candidates
|
||||
.map { Base64.encodeUrlSafeWithoutPadding(it.hash) }
|
||||
|
||||
return when (val result = SignalNetwork.account.reserveUsername(hashes)) {
|
||||
is NetworkResult.Success -> {
|
||||
val hashIndex = hashes.indexOf(result.result.usernameHash)
|
||||
if (hashIndex == -1) {
|
||||
Log.w(TAG, "[reserveUsername] The response hash could not be found in our set of hashes.")
|
||||
return failure(UsernameSetResult.CANDIDATE_GENERATION_ERROR)
|
||||
}
|
||||
|
||||
Log.i(TAG, "[reserveUsername] Successfully reserved username.")
|
||||
success(UsernameState.Reserved(candidates[hashIndex]))
|
||||
}
|
||||
is NetworkResult.StatusCodeError -> {
|
||||
when (result.code) {
|
||||
409 -> {
|
||||
Log.w(TAG, "[reserveUsername] Username taken.")
|
||||
failure(UsernameSetResult.USERNAME_UNAVAILABLE)
|
||||
}
|
||||
422 -> {
|
||||
Log.w(TAG, "[reserveUsername] Username malformed.")
|
||||
failure(UsernameSetResult.USERNAME_INVALID)
|
||||
}
|
||||
429 -> {
|
||||
Log.w(TAG, "[reserveUsername] Rate limit exceeded.")
|
||||
failure(UsernameSetResult.RATE_LIMIT_ERROR)
|
||||
}
|
||||
else -> {
|
||||
Log.w(TAG, "[reserveUsername] Generic network exception.", result.exception)
|
||||
failure(UsernameSetResult.NETWORK_ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
is NetworkResult.NetworkError -> {
|
||||
Log.w(TAG, "[reserveUsername] Generic network exception.", result.exception)
|
||||
failure(UsernameSetResult.NETWORK_ERROR)
|
||||
}
|
||||
is NetworkResult.ApplicationError -> throw result.throwable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,25 +435,27 @@ object UsernameRepository {
|
||||
return UsernameSetResult.NETWORK_ERROR
|
||||
}
|
||||
|
||||
return try {
|
||||
val oldUsernameLink = SignalStore.account.usernameLink ?: return UsernameSetResult.USERNAME_INVALID
|
||||
val newUsernameLink = updatedUsername.generateLink(oldUsernameLink.entropy)
|
||||
val usernameLinkComponents = accountManager.updateUsernameLink(newUsernameLink)
|
||||
val oldUsernameLink = SignalStore.account.usernameLink ?: return UsernameSetResult.USERNAME_INVALID
|
||||
val newUsernameLink = updatedUsername.generateLink(oldUsernameLink.entropy)
|
||||
|
||||
SignalStore.account.username = updatedUsername.username
|
||||
SignalStore.account.usernameLink = usernameLinkComponents
|
||||
SignalDatabase.recipients.setUsername(Recipient.self().id, updatedUsername.username)
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
return when (val result = SignalNetwork.account.updateUsernameLink(newUsernameLink)) {
|
||||
is NetworkResult.Success -> {
|
||||
SignalStore.account.username = updatedUsername.username
|
||||
SignalStore.account.usernameLink = result.result
|
||||
SignalDatabase.recipients.setUsername(Recipient.self().id, updatedUsername.username)
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.i(TAG, "[updateUsernameDisplayForCurrentLink] Successfully updated username.")
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.i(TAG, "[updateUsernameDisplayForCurrentLink] Successfully updated username.")
|
||||
|
||||
UsernameSetResult.SUCCESS
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[updateUsernameDisplayForCurrentLink] Generic network exception.", e)
|
||||
UsernameSetResult.NETWORK_ERROR
|
||||
UsernameSetResult.SUCCESS
|
||||
}
|
||||
else -> {
|
||||
Log.w(TAG, "[updateUsernameDisplayForCurrentLink] Generic network exception.", result.getCause())
|
||||
UsernameSetResult.NETWORK_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,32 +468,55 @@ object UsernameRepository {
|
||||
return UsernameSetResult.NETWORK_ERROR
|
||||
}
|
||||
|
||||
return try {
|
||||
val linkComponents: UsernameLinkComponents = accountManager.confirmUsernameAndCreateNewLink(username)
|
||||
val link = username.generateLink()
|
||||
|
||||
SignalStore.account.username = username.username
|
||||
SignalStore.account.usernameLink = linkComponents
|
||||
SignalDatabase.recipients.setUsername(Recipient.self().id, username.username)
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
return when (val result = SignalNetwork.account.confirmUsername(username, link)) {
|
||||
is NetworkResult.Success -> {
|
||||
SignalStore.account.username = username.username
|
||||
SignalStore.account.usernameLink = UsernameLinkComponents(link.entropy, result.result)
|
||||
SignalDatabase.recipients.setUsername(Recipient.self().id, username.username)
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.i(TAG, "[confirmUsernameAndCreateNewLink] Successfully confirmed username.")
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.i(TAG, "[confirmUsernameAndCreateNewLink] Successfully confirmed username.")
|
||||
|
||||
UsernameSetResult.SUCCESS
|
||||
} catch (e: UsernameTakenException) {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username gone.")
|
||||
UsernameSetResult.USERNAME_UNAVAILABLE
|
||||
} catch (e: UsernameIsNotReservedException) {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username was not reserved.")
|
||||
UsernameSetResult.USERNAME_INVALID
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username was not reserved.")
|
||||
UsernameSetResult.USERNAME_INVALID
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Generic network exception.", e)
|
||||
UsernameSetResult.NETWORK_ERROR
|
||||
UsernameSetResult.SUCCESS
|
||||
}
|
||||
|
||||
is NetworkResult.StatusCodeError -> {
|
||||
when (result.code) {
|
||||
409 -> {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username was not reserved.")
|
||||
UsernameSetResult.USERNAME_INVALID
|
||||
}
|
||||
|
||||
410 -> {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username gone.")
|
||||
UsernameSetResult.USERNAME_UNAVAILABLE
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Generic network exception.", result.exception)
|
||||
UsernameSetResult.NETWORK_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is NetworkResult.NetworkError -> {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Generic network exception.", result.exception)
|
||||
UsernameSetResult.NETWORK_ERROR
|
||||
}
|
||||
|
||||
is NetworkResult.ApplicationError -> {
|
||||
if (result.throwable is BaseUsernameException) {
|
||||
Log.w(TAG, "[confirmUsernameAndCreateNewLink] Username was not reserved.")
|
||||
UsernameSetResult.USERNAME_INVALID
|
||||
} else {
|
||||
throw result.throwable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,43 +527,65 @@ object UsernameRepository {
|
||||
return UsernameDeleteResult.NETWORK_ERROR
|
||||
}
|
||||
|
||||
return try {
|
||||
accountManager.deleteUsername()
|
||||
SignalDatabase.recipients.setUsername(Recipient.self().id, null)
|
||||
SignalStore.account.username = null
|
||||
SignalStore.account.usernameLink = null
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.i(TAG, "[deleteUsername] Successfully deleted the username.")
|
||||
UsernameDeleteResult.SUCCESS
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[deleteUsername] Generic network exception.", e)
|
||||
UsernameDeleteResult.NETWORK_ERROR
|
||||
return when (val result = SignalNetwork.account.deleteUsername()) {
|
||||
is NetworkResult.Success -> {
|
||||
SignalDatabase.recipients.setUsername(Recipient.self().id, null)
|
||||
SignalStore.account.username = null
|
||||
SignalStore.account.usernameLink = null
|
||||
SignalStore.account.usernameSyncState = AccountValues.UsernameSyncState.IN_SYNC
|
||||
SignalStore.account.usernameSyncErrorCount = 0
|
||||
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
Log.i(TAG, "[deleteUsername] Successfully deleted the username.")
|
||||
UsernameDeleteResult.SUCCESS
|
||||
}
|
||||
else -> {
|
||||
Log.w(TAG, "[deleteUsername] Generic network exception.", result.getCause())
|
||||
UsernameDeleteResult.NETWORK_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@JvmStatic
|
||||
private fun reclaimUsernameIfNecessaryInternal(username: Username, usernameLinkComponents: UsernameLinkComponents): UsernameReclaimResult {
|
||||
try {
|
||||
accountManager.reclaimUsernameAndLink(username, usernameLinkComponents)
|
||||
} catch (e: UsernameTakenException) {
|
||||
Log.w(TAG, "[reclaimUsername] Username gone.")
|
||||
return UsernameReclaimResult.PERMANENT_ERROR
|
||||
} catch (e: UsernameIsNotReservedException) {
|
||||
Log.w(TAG, "[reclaimUsername] Username was not reserved.")
|
||||
return UsernameReclaimResult.PERMANENT_ERROR
|
||||
} catch (e: BaseUsernameException) {
|
||||
Log.w(TAG, "[reclaimUsername] Invalid username.")
|
||||
return UsernameReclaimResult.PERMANENT_ERROR
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "[reclaimUsername] Network error.", e)
|
||||
return UsernameReclaimResult.NETWORK_ERROR
|
||||
}
|
||||
val link = username.generateLink(usernameLinkComponents.entropy)
|
||||
|
||||
return UsernameReclaimResult.SUCCESS
|
||||
return when (val result = SignalNetwork.account.confirmUsername(username, link)) {
|
||||
is NetworkResult.Success -> UsernameReclaimResult.SUCCESS
|
||||
is NetworkResult.StatusCodeError -> {
|
||||
when (result.code) {
|
||||
409 -> {
|
||||
Log.w(TAG, "[reclaimUsername] Username was not reserved.")
|
||||
UsernameReclaimResult.PERMANENT_ERROR
|
||||
}
|
||||
|
||||
410 -> {
|
||||
Log.w(TAG, "[reclaimUsername] Username gone.")
|
||||
UsernameReclaimResult.PERMANENT_ERROR
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.w(TAG, "[reclaimUsername] Network error.", result.exception)
|
||||
UsernameReclaimResult.NETWORK_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is NetworkResult.NetworkError -> {
|
||||
Log.w(TAG, "[reclaimUsername] Network error.", result.exception)
|
||||
UsernameReclaimResult.NETWORK_ERROR
|
||||
}
|
||||
|
||||
is NetworkResult.ApplicationError -> {
|
||||
if (result.throwable is BaseUsernameException) {
|
||||
Log.w(TAG, "[reclaimUsername] Invalid username.")
|
||||
UsernameReclaimResult.PERMANENT_ERROR
|
||||
} else {
|
||||
throw result.throwable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class UsernameSetResult {
|
||||
|
||||
@@ -13,7 +13,6 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import org.signal.core.util.concurrent.safeBlockingGet
|
||||
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientRepository
|
||||
@@ -66,7 +65,7 @@ class FindByViewModel(
|
||||
return FindByResult.InvalidEntry
|
||||
}
|
||||
|
||||
return when (val result = UsernameRepository.fetchAciForUsername(username = username).safeBlockingGet()) {
|
||||
return when (val result = UsernameRepository.fetchAciForUsername(usernameString = username)) {
|
||||
UsernameRepository.UsernameAciFetchResult.NetworkError -> FindByResult.NotFound()
|
||||
UsernameRepository.UsernameAciFetchResult.NotFound -> FindByResult.NotFound()
|
||||
is UsernameRepository.UsernameAciFetchResult.Success -> FindByResult.Success(Recipient.externalUsername(result.aci, username).id)
|
||||
|
||||
Reference in New Issue
Block a user