mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-20 11:08:31 +00:00
Update ktlint to 1.5.0.
This commit is contained in:
@@ -78,7 +78,7 @@ wire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ktlint {
|
ktlint {
|
||||||
version.set("1.2.1")
|
version.set("1.5.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|||||||
@@ -162,7 +162,9 @@ class DatabaseAttachment : Attachment {
|
|||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return other != null &&
|
return other != null &&
|
||||||
other is DatabaseAttachment && other.attachmentId == attachmentId && other.uri == uri
|
other is DatabaseAttachment &&
|
||||||
|
other.attachmentId == attachmentId &&
|
||||||
|
other.uri == uri
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
|
|||||||
@@ -48,22 +48,19 @@ class SystemEmojiDrawable(emoji: CharSequence) : Drawable() {
|
|||||||
companion object {
|
companion object {
|
||||||
private val textPaint: TextPaint = TextPaint()
|
private val textPaint: TextPaint = TextPaint()
|
||||||
|
|
||||||
private fun getStaticLayout(emoji: CharSequence): StaticLayout =
|
private fun getStaticLayout(emoji: CharSequence): StaticLayout = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
StaticLayout.Builder.obtain(emoji, 0, emoji.length, textPaint, Int.MAX_VALUE).build()
|
||||||
StaticLayout.Builder.obtain(emoji, 0, emoji.length, textPaint, Int.MAX_VALUE).build()
|
} else {
|
||||||
} else {
|
@Suppress("DEPRECATION")
|
||||||
@Suppress("DEPRECATION")
|
StaticLayout(emoji, textPaint, Int.MAX_VALUE, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
|
||||||
StaticLayout(emoji, textPaint, Int.MAX_VALUE, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun getProcessedEmoji(emoji: CharSequence): CharSequence =
|
private fun getProcessedEmoji(emoji: CharSequence): CharSequence = try {
|
||||||
try {
|
EmojiCompat.get().process(emoji) ?: emoji
|
||||||
EmojiCompat.get().process(emoji) ?: emoji
|
} catch (e: IllegalStateException) {
|
||||||
} catch (e: IllegalStateException) {
|
emoji
|
||||||
emoji
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun StaticLayout.getBounds(): RectF =
|
private fun StaticLayout.getBounds(): RectF = RectF(getLineLeft(0), 0f, getLineRight(0), getLineDescent(0) - getLineAscent(0).toFloat())
|
||||||
RectF(getLineLeft(0), 0f, getLineRight(0), getLineDescent(0) - getLineAscent(0).toFloat())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,14 +36,11 @@ sealed class DSLSettingsText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun from(@StringRes stringId: Int, @ColorInt textColor: Int): DSLSettingsText =
|
fun from(@StringRes stringId: Int, @ColorInt textColor: Int): DSLSettingsText = FromResource(stringId, listOf(ColorModifier(textColor)))
|
||||||
FromResource(stringId, listOf(ColorModifier(textColor)))
|
|
||||||
|
|
||||||
fun from(@StringRes stringId: Int, vararg modifiers: Modifier): DSLSettingsText =
|
fun from(@StringRes stringId: Int, vararg modifiers: Modifier): DSLSettingsText = FromResource(stringId, modifiers.toList())
|
||||||
FromResource(stringId, modifiers.toList())
|
|
||||||
|
|
||||||
fun from(charSequence: CharSequence, vararg modifiers: Modifier): DSLSettingsText =
|
fun from(charSequence: CharSequence, vararg modifiers: Modifier): DSLSettingsText = FromCharSequence(charSequence, modifiers.toList())
|
||||||
FromCharSequence(charSequence, modifiers.toList())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Modifier {
|
interface Modifier {
|
||||||
|
|||||||
@@ -267,7 +267,8 @@ class BackupStateObserver(
|
|||||||
Log.d(TAG, "[getNetworkBackupState][subscriptionStateMismatchDetected] No purchase found in Google Play Billing: $purchaseResult")
|
Log.d(TAG, "[getNetworkBackupState][subscriptionStateMismatchDetected] No purchase found in Google Play Billing: $purchaseResult")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} || SignalStore.backup.backupTierInternalOverride == MessageBackupTier.PAID
|
} ||
|
||||||
|
SignalStore.backup.backupTierInternalOverride == MessageBackupTier.PAID
|
||||||
|
|
||||||
Log.d(TAG, "[getNetworkBackupState][subscriptionStateMismatchDetected] googlePlayBillingSubscriptionIsActiveAndWillRenew: $googlePlayBillingSubscriptionIsActiveAndWillRenew")
|
Log.d(TAG, "[getNetworkBackupState][subscriptionStateMismatchDetected] googlePlayBillingSubscriptionIsActiveAndWillRenew: $googlePlayBillingSubscriptionIsActiveAndWillRenew")
|
||||||
|
|
||||||
|
|||||||
@@ -75,32 +75,31 @@ class ChangeNumberRepository(
|
|||||||
return accountManager.whoAmI
|
return accountManager.whoAmI
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun ensureDecryptionsDrained(timeout: Duration = 15.seconds) =
|
suspend fun ensureDecryptionsDrained(timeout: Duration = 15.seconds) = withTimeoutOrNull(timeout) {
|
||||||
withTimeoutOrNull(timeout) {
|
suspendCancellableCoroutine {
|
||||||
suspendCancellableCoroutine {
|
val drainedListener = object : Runnable {
|
||||||
val drainedListener = object : Runnable {
|
override fun run() {
|
||||||
override fun run() {
|
|
||||||
AppDependencies
|
|
||||||
.incomingMessageObserver
|
|
||||||
.removeDecryptionDrainedListener(this)
|
|
||||||
Log.d(TAG, "Decryptions drained.")
|
|
||||||
it.resume(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
it.invokeOnCancellation { cancellationCause ->
|
|
||||||
AppDependencies
|
AppDependencies
|
||||||
.incomingMessageObserver
|
.incomingMessageObserver
|
||||||
.removeDecryptionDrainedListener(drainedListener)
|
.removeDecryptionDrainedListener(this)
|
||||||
Log.d(TAG, "Decryptions draining canceled.", cancellationCause)
|
Log.d(TAG, "Decryptions drained.")
|
||||||
|
it.resume(true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it.invokeOnCancellation { cancellationCause ->
|
||||||
AppDependencies
|
AppDependencies
|
||||||
.incomingMessageObserver
|
.incomingMessageObserver
|
||||||
.addDecryptionDrainedListener(drainedListener)
|
.removeDecryptionDrainedListener(drainedListener)
|
||||||
Log.d(TAG, "Waiting for decryption drain.")
|
Log.d(TAG, "Decryptions draining canceled.", cancellationCause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppDependencies
|
||||||
|
.incomingMessageObserver
|
||||||
|
.addDecryptionDrainedListener(drainedListener)
|
||||||
|
Log.d(TAG, "Waiting for decryption drain.")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
fun changeLocalNumber(e164: String, pni: ServiceId.PNI) {
|
fun changeLocalNumber(e164: String, pni: ServiceId.PNI) {
|
||||||
|
|||||||
@@ -140,11 +140,12 @@ class NotificationsSettingsViewModel(private val sharedPreferences: SharedPrefer
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun canEnableNotifications(): Boolean {
|
private fun canEnableNotifications(): Boolean {
|
||||||
val areNotificationsDisabledBySystem = Build.VERSION.SDK_INT >= 26 && (
|
val areNotificationsDisabledBySystem = Build.VERSION.SDK_INT >= 26 &&
|
||||||
!NotificationChannels.getInstance().isMessageChannelEnabled ||
|
(
|
||||||
!NotificationChannels.getInstance().isMessagesChannelGroupEnabled ||
|
!NotificationChannels.getInstance().isMessageChannelEnabled ||
|
||||||
!NotificationChannels.getInstance().areNotificationsEnabled()
|
!NotificationChannels.getInstance().isMessagesChannelGroupEnabled ||
|
||||||
)
|
!NotificationChannels.getInstance().areNotificationsEnabled()
|
||||||
|
)
|
||||||
|
|
||||||
return !areNotificationsDisabledBySystem
|
return !areNotificationsDisabledBySystem
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ object InAppDonations {
|
|||||||
InAppPaymentType.ONE_TIME_GIFT -> true
|
InAppPaymentType.ONE_TIME_GIFT -> true
|
||||||
InAppPaymentType.RECURRING_DONATION -> true
|
InAppPaymentType.RECURRING_DONATION -> true
|
||||||
InAppPaymentType.RECURRING_BACKUP -> false
|
InAppPaymentType.RECURRING_BACKUP -> false
|
||||||
} && !LocaleRemoteConfig.isPayPalDisabled()
|
} &&
|
||||||
|
!LocaleRemoteConfig.isPayPalDisabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -178,12 +178,10 @@ class ChatColors(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun forGradient(id: Id, linearGradient: LinearGradient): ChatColors =
|
fun forGradient(id: Id, linearGradient: LinearGradient): ChatColors = ChatColors(id, linearGradient, null)
|
||||||
ChatColors(id, linearGradient, null)
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun forColor(id: Id, @ColorInt color: Int): ChatColors =
|
fun forColor(id: Id, @ColorInt color: Int): ChatColors = ChatColors(id, null, color)
|
||||||
ChatColors(id, null, color)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Id(val longValue: Long) : Parcelable {
|
sealed class Id(val longValue: Long) : Parcelable {
|
||||||
|
|||||||
@@ -423,12 +423,13 @@ object SvrRepository {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
newToken = newToken || if (Svr3Migration.shouldWriteToSvr2) {
|
newToken = newToken ||
|
||||||
val credentials: AuthCredentials = svr2.authorization()
|
if (Svr3Migration.shouldWriteToSvr2) {
|
||||||
SignalStore.svr.appendSvr2AuthTokenToList(credentials.asBasic())
|
val credentials: AuthCredentials = svr2.authorization()
|
||||||
} else {
|
SignalStore.svr.appendSvr2AuthTokenToList(credentials.asBasic())
|
||||||
false
|
} else {
|
||||||
}
|
false
|
||||||
|
}
|
||||||
|
|
||||||
if (newToken && SignalStore.svr.hasPin()) {
|
if (newToken && SignalStore.svr.hasPin()) {
|
||||||
BackupManager(AppDependencies.application).dataChanged()
|
BackupManager(AppDependencies.application).dataChanged()
|
||||||
|
|||||||
@@ -110,10 +110,9 @@ object RegistrationRepository {
|
|||||||
/**
|
/**
|
||||||
* Retrieve the FCM token from the Firebase service.
|
* Retrieve the FCM token from the Firebase service.
|
||||||
*/
|
*/
|
||||||
suspend fun getFcmToken(context: Context): String? =
|
suspend fun getFcmToken(context: Context): String? = withContext(Dispatchers.Default) {
|
||||||
withContext(Dispatchers.Default) {
|
FcmUtil.getToken(context).orElse(null)
|
||||||
FcmUtil.getToken(context).orElse(null)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries, and creates if needed, the local registration ID.
|
* Queries, and creates if needed, the local registration ID.
|
||||||
@@ -147,122 +146,120 @@ object RegistrationRepository {
|
|||||||
* Queries, and creates if needed, the local profile key.
|
* Queries, and creates if needed, the local profile key.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
suspend fun getProfileKey(e164: String): ProfileKey =
|
suspend fun getProfileKey(e164: String): ProfileKey = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
// TODO [regv2]: make creation more explicit instead of hiding it in this getter
|
||||||
// TODO [regv2]: make creation more explicit instead of hiding it in this getter
|
val recipientTable = SignalDatabase.recipients
|
||||||
val recipientTable = SignalDatabase.recipients
|
val recipient = recipientTable.getByE164(e164)
|
||||||
val recipient = recipientTable.getByE164(e164)
|
var profileKey = if (recipient.isPresent) {
|
||||||
var profileKey = if (recipient.isPresent) {
|
ProfileKeyUtil.profileKeyOrNull(Recipient.resolved(recipient.get()).profileKey)
|
||||||
ProfileKeyUtil.profileKeyOrNull(Recipient.resolved(recipient.get()).profileKey)
|
} else {
|
||||||
} else {
|
null
|
||||||
null
|
|
||||||
}
|
|
||||||
if (profileKey == null) {
|
|
||||||
profileKey = ProfileKeyUtil.createNew()
|
|
||||||
Log.i(TAG, "No profile key found, created a new one")
|
|
||||||
}
|
|
||||||
profileKey
|
|
||||||
}
|
}
|
||||||
|
if (profileKey == null) {
|
||||||
|
profileKey = ProfileKeyUtil.createNew()
|
||||||
|
Log.i(TAG, "No profile key found, created a new one")
|
||||||
|
}
|
||||||
|
profileKey
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a server response from a successful registration and persists the relevant data.
|
* Takes a server response from a successful registration and persists the relevant data.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
suspend fun registerAccountLocally(context: Context, data: LocalRegistrationMetadata) =
|
suspend fun registerAccountLocally(context: Context, data: LocalRegistrationMetadata) = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
Log.v(TAG, "registerAccountLocally()")
|
||||||
Log.v(TAG, "registerAccountLocally()")
|
if (data.linkedDeviceInfo != null) {
|
||||||
if (data.linkedDeviceInfo != null) {
|
SignalStore.account.deviceId = data.linkedDeviceInfo.deviceId
|
||||||
SignalStore.account.deviceId = data.linkedDeviceInfo.deviceId
|
SignalStore.account.deviceName = data.linkedDeviceInfo.deviceName
|
||||||
SignalStore.account.deviceName = data.linkedDeviceInfo.deviceName
|
}
|
||||||
|
|
||||||
|
val aciIdentityKeyPair = data.getAciIdentityKeyPair()
|
||||||
|
val pniIdentityKeyPair = data.getPniIdentityKeyPair()
|
||||||
|
SignalStore.account.restoreAciIdentityKeyFromBackup(aciIdentityKeyPair.publicKey.serialize(), aciIdentityKeyPair.privateKey.serialize())
|
||||||
|
SignalStore.account.restorePniIdentityKeyFromBackup(pniIdentityKeyPair.publicKey.serialize(), pniIdentityKeyPair.privateKey.serialize())
|
||||||
|
|
||||||
|
val aciPreKeyCollection = data.getAciPreKeyCollection()
|
||||||
|
val pniPreKeyCollection = data.getPniPreKeyCollection()
|
||||||
|
val aci: ACI = ACI.parseOrThrow(data.aci)
|
||||||
|
val pni: PNI = PNI.parseOrThrow(data.pni)
|
||||||
|
val hasPin: Boolean = data.hasPin
|
||||||
|
|
||||||
|
SignalStore.account.setAci(aci)
|
||||||
|
SignalStore.account.setPni(pni)
|
||||||
|
|
||||||
|
AppDependencies.resetProtocolStores()
|
||||||
|
|
||||||
|
AppDependencies.protocolStore.aci().sessions().archiveAllSessions()
|
||||||
|
AppDependencies.protocolStore.pni().sessions().archiveAllSessions()
|
||||||
|
SenderKeyUtil.clearAllState()
|
||||||
|
|
||||||
|
val aciProtocolStore = AppDependencies.protocolStore.aci()
|
||||||
|
val aciMetadataStore = SignalStore.account.aciPreKeys
|
||||||
|
|
||||||
|
val pniProtocolStore = AppDependencies.protocolStore.pni()
|
||||||
|
val pniMetadataStore = SignalStore.account.pniPreKeys
|
||||||
|
|
||||||
|
storeSignedAndLastResortPreKeys(aciProtocolStore, aciMetadataStore, aciPreKeyCollection)
|
||||||
|
storeSignedAndLastResortPreKeys(pniProtocolStore, pniMetadataStore, pniPreKeyCollection)
|
||||||
|
|
||||||
|
val recipientTable = SignalDatabase.recipients
|
||||||
|
val selfId = Recipient.trustedPush(aci, pni, data.e164).id
|
||||||
|
|
||||||
|
recipientTable.setProfileSharing(selfId, true)
|
||||||
|
recipientTable.markRegisteredOrThrow(selfId, aci)
|
||||||
|
recipientTable.linkIdsForSelf(aci, pni, data.e164)
|
||||||
|
recipientTable.setProfileKey(selfId, ProfileKey(data.profileKey.toByteArray()))
|
||||||
|
|
||||||
|
AppDependencies.recipientCache.clearSelf()
|
||||||
|
|
||||||
|
SignalStore.account.setE164(data.e164)
|
||||||
|
SignalStore.account.fcmToken = data.fcmToken
|
||||||
|
SignalStore.account.fcmEnabled = data.fcmEnabled
|
||||||
|
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
saveOwnIdentityKey(selfId, aci, aciProtocolStore, now)
|
||||||
|
saveOwnIdentityKey(selfId, pni, pniProtocolStore, now)
|
||||||
|
|
||||||
|
if (data.linkedDeviceInfo != null) {
|
||||||
|
if (data.linkedDeviceInfo.accountEntropyPool != null) {
|
||||||
|
SignalStore.account.setAccountEntropyPoolFromPrimaryDevice(AccountEntropyPool(data.linkedDeviceInfo.accountEntropyPool))
|
||||||
}
|
}
|
||||||
|
|
||||||
val aciIdentityKeyPair = data.getAciIdentityKeyPair()
|
if (data.linkedDeviceInfo.mediaRootBackupKey != null) {
|
||||||
val pniIdentityKeyPair = data.getPniIdentityKeyPair()
|
SignalStore.backup.mediaRootBackupKey = MediaRootBackupKey(data.linkedDeviceInfo.mediaRootBackupKey.toByteArray())
|
||||||
SignalStore.account.restoreAciIdentityKeyFromBackup(aciIdentityKeyPair.publicKey.serialize(), aciIdentityKeyPair.privateKey.serialize())
|
|
||||||
SignalStore.account.restorePniIdentityKeyFromBackup(pniIdentityKeyPair.publicKey.serialize(), pniIdentityKeyPair.privateKey.serialize())
|
|
||||||
|
|
||||||
val aciPreKeyCollection = data.getAciPreKeyCollection()
|
|
||||||
val pniPreKeyCollection = data.getPniPreKeyCollection()
|
|
||||||
val aci: ACI = ACI.parseOrThrow(data.aci)
|
|
||||||
val pni: PNI = PNI.parseOrThrow(data.pni)
|
|
||||||
val hasPin: Boolean = data.hasPin
|
|
||||||
|
|
||||||
SignalStore.account.setAci(aci)
|
|
||||||
SignalStore.account.setPni(pni)
|
|
||||||
|
|
||||||
AppDependencies.resetProtocolStores()
|
|
||||||
|
|
||||||
AppDependencies.protocolStore.aci().sessions().archiveAllSessions()
|
|
||||||
AppDependencies.protocolStore.pni().sessions().archiveAllSessions()
|
|
||||||
SenderKeyUtil.clearAllState()
|
|
||||||
|
|
||||||
val aciProtocolStore = AppDependencies.protocolStore.aci()
|
|
||||||
val aciMetadataStore = SignalStore.account.aciPreKeys
|
|
||||||
|
|
||||||
val pniProtocolStore = AppDependencies.protocolStore.pni()
|
|
||||||
val pniMetadataStore = SignalStore.account.pniPreKeys
|
|
||||||
|
|
||||||
storeSignedAndLastResortPreKeys(aciProtocolStore, aciMetadataStore, aciPreKeyCollection)
|
|
||||||
storeSignedAndLastResortPreKeys(pniProtocolStore, pniMetadataStore, pniPreKeyCollection)
|
|
||||||
|
|
||||||
val recipientTable = SignalDatabase.recipients
|
|
||||||
val selfId = Recipient.trustedPush(aci, pni, data.e164).id
|
|
||||||
|
|
||||||
recipientTable.setProfileSharing(selfId, true)
|
|
||||||
recipientTable.markRegisteredOrThrow(selfId, aci)
|
|
||||||
recipientTable.linkIdsForSelf(aci, pni, data.e164)
|
|
||||||
recipientTable.setProfileKey(selfId, ProfileKey(data.profileKey.toByteArray()))
|
|
||||||
|
|
||||||
AppDependencies.recipientCache.clearSelf()
|
|
||||||
|
|
||||||
SignalStore.account.setE164(data.e164)
|
|
||||||
SignalStore.account.fcmToken = data.fcmToken
|
|
||||||
SignalStore.account.fcmEnabled = data.fcmEnabled
|
|
||||||
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
saveOwnIdentityKey(selfId, aci, aciProtocolStore, now)
|
|
||||||
saveOwnIdentityKey(selfId, pni, pniProtocolStore, now)
|
|
||||||
|
|
||||||
if (data.linkedDeviceInfo != null) {
|
|
||||||
if (data.linkedDeviceInfo.accountEntropyPool != null) {
|
|
||||||
SignalStore.account.setAccountEntropyPoolFromPrimaryDevice(AccountEntropyPool(data.linkedDeviceInfo.accountEntropyPool))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.linkedDeviceInfo.mediaRootBackupKey != null) {
|
|
||||||
SignalStore.backup.mediaRootBackupKey = MediaRootBackupKey(data.linkedDeviceInfo.mediaRootBackupKey.toByteArray())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SignalStore.account.setServicePassword(data.servicePassword)
|
|
||||||
SignalStore.account.setRegistered(true)
|
|
||||||
TextSecurePreferences.setPromptedPushRegistration(context, true)
|
|
||||||
TextSecurePreferences.setUnauthorizedReceived(context, false)
|
|
||||||
NotificationManagerCompat.from(context).cancel(NotificationIds.UNREGISTERED_NOTIFICATION_ID)
|
|
||||||
|
|
||||||
val masterKey = if (data.masterKey != null) MasterKey(data.masterKey.toByteArray()) else null
|
|
||||||
SvrRepository.onRegistrationComplete(masterKey, data.pin, hasPin, data.reglockEnabled, SignalStore.account.restoredAccountEntropyPool)
|
|
||||||
|
|
||||||
AppDependencies.resetNetwork()
|
|
||||||
AppDependencies.startNetwork()
|
|
||||||
PreKeysSyncJob.enqueue()
|
|
||||||
|
|
||||||
val jobManager = AppDependencies.jobManager
|
|
||||||
|
|
||||||
if (data.linkedDeviceInfo == null) {
|
|
||||||
jobManager.add(DirectoryRefreshJob(false))
|
|
||||||
jobManager.add(RotateCertificateJob())
|
|
||||||
|
|
||||||
DirectoryRefreshListener.schedule(context)
|
|
||||||
RotateSignedPreKeyListener.schedule(context)
|
|
||||||
} else {
|
|
||||||
SignalStore.account.isMultiDevice = true
|
|
||||||
jobManager.runJobBlocking(RefreshOwnProfileJob(), 30.seconds)
|
|
||||||
|
|
||||||
jobManager.add(RotateCertificateJob())
|
|
||||||
RotateSignedPreKeyListener.schedule(context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SignalStore.account.setServicePassword(data.servicePassword)
|
||||||
|
SignalStore.account.setRegistered(true)
|
||||||
|
TextSecurePreferences.setPromptedPushRegistration(context, true)
|
||||||
|
TextSecurePreferences.setUnauthorizedReceived(context, false)
|
||||||
|
NotificationManagerCompat.from(context).cancel(NotificationIds.UNREGISTERED_NOTIFICATION_ID)
|
||||||
|
|
||||||
|
val masterKey = if (data.masterKey != null) MasterKey(data.masterKey.toByteArray()) else null
|
||||||
|
SvrRepository.onRegistrationComplete(masterKey, data.pin, hasPin, data.reglockEnabled, SignalStore.account.restoredAccountEntropyPool)
|
||||||
|
|
||||||
|
AppDependencies.resetNetwork()
|
||||||
|
AppDependencies.startNetwork()
|
||||||
|
PreKeysSyncJob.enqueue()
|
||||||
|
|
||||||
|
val jobManager = AppDependencies.jobManager
|
||||||
|
|
||||||
|
if (data.linkedDeviceInfo == null) {
|
||||||
|
jobManager.add(DirectoryRefreshJob(false))
|
||||||
|
jobManager.add(RotateCertificateJob())
|
||||||
|
|
||||||
|
DirectoryRefreshListener.schedule(context)
|
||||||
|
RotateSignedPreKeyListener.schedule(context)
|
||||||
|
} else {
|
||||||
|
SignalStore.account.isMultiDevice = true
|
||||||
|
jobManager.runJobBlocking(RefreshOwnProfileJob(), 30.seconds)
|
||||||
|
|
||||||
|
jobManager.add(RotateCertificateJob())
|
||||||
|
RotateSignedPreKeyListener.schedule(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private fun saveOwnIdentityKey(selfId: RecipientId, serviceId: ServiceId, protocolStore: SignalServiceAccountDataStoreImpl, now: Long) {
|
private fun saveOwnIdentityKey(selfId: RecipientId, serviceId: ServiceId, protocolStore: SignalServiceAccountDataStoreImpl, now: Long) {
|
||||||
protocolStore.identities().saveIdentityWithoutSideEffects(
|
protocolStore.identities().saveIdentityWithoutSideEffects(
|
||||||
@@ -299,49 +296,46 @@ object RegistrationRepository {
|
|||||||
return PinHashUtil.verifyLocalPinHash(pinHash, pin)
|
return PinHashUtil.verifyLocalPinHash(pinHash, pin)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fetchMasterKeyFromSvrRemote(pin: String, svr2Credentials: AuthCredentials?, svr3Credentials: Svr3Credentials?): MasterKey =
|
suspend fun fetchMasterKeyFromSvrRemote(pin: String, svr2Credentials: AuthCredentials?, svr3Credentials: Svr3Credentials?): MasterKey = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val credentialSet = SvrAuthCredentialSet(svr2Credentials = svr2Credentials, svr3Credentials = svr3Credentials)
|
||||||
val credentialSet = SvrAuthCredentialSet(svr2Credentials = svr2Credentials, svr3Credentials = svr3Credentials)
|
val masterKey = SvrRepository.restoreMasterKeyPreRegistration(credentialSet, pin)
|
||||||
val masterKey = SvrRepository.restoreMasterKeyPreRegistration(credentialSet, pin)
|
return@withContext masterKey
|
||||||
return@withContext masterKey
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a session ID.
|
* Validates a session ID.
|
||||||
*/
|
*/
|
||||||
private suspend fun validateSession(context: Context, sessionId: String, e164: String, password: String): RegistrationSessionCheckResult =
|
private suspend fun validateSession(context: Context, sessionId: String, e164: String, password: String): RegistrationSessionCheckResult = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
Log.d(TAG, "Validating registration session with service.")
|
||||||
Log.d(TAG, "Validating registration session with service.")
|
val registrationSessionResult = api.getRegistrationSessionStatus(sessionId)
|
||||||
val registrationSessionResult = api.getRegistrationSessionStatus(sessionId)
|
return@withContext RegistrationSessionCheckResult.from(registrationSessionResult)
|
||||||
return@withContext RegistrationSessionCheckResult.from(registrationSessionResult)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a new registration session on the service.
|
* Initiates a new registration session on the service.
|
||||||
*/
|
*/
|
||||||
suspend fun createSession(context: Context, e164: String, password: String, mcc: String?, mnc: String?): RegistrationSessionCreationResult =
|
suspend fun createSession(context: Context, e164: String, password: String, mcc: String?, mnc: String?): RegistrationSessionCreationResult = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
Log.d(TAG, "About to create a registration session…")
|
||||||
Log.d(TAG, "About to create a registration session…")
|
val fcmToken: String? = FcmUtil.getToken(context).orElse(null)
|
||||||
val fcmToken: String? = FcmUtil.getToken(context).orElse(null)
|
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
|
||||||
|
|
||||||
val registrationSessionResult = if (fcmToken == null) {
|
val registrationSessionResult = if (fcmToken == null) {
|
||||||
Log.d(TAG, "Creating registration session without FCM token.")
|
Log.d(TAG, "Creating registration session without FCM token.")
|
||||||
api.createRegistrationSession(null, mcc, mnc)
|
api.createRegistrationSession(null, mcc, mnc)
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Creating registration session with FCM token.")
|
Log.d(TAG, "Creating registration session with FCM token.")
|
||||||
createSessionAndBlockForPushChallenge(api, fcmToken, mcc, mnc)
|
createSessionAndBlockForPushChallenge(api, fcmToken, mcc, mnc)
|
||||||
}
|
|
||||||
val result = RegistrationSessionCreationResult.from(registrationSessionResult)
|
|
||||||
if (result is RegistrationSessionCreationResult.Success) {
|
|
||||||
Log.d(TAG, "Updating registration session and E164 in value store.")
|
|
||||||
SignalStore.registration.sessionId = result.sessionId
|
|
||||||
SignalStore.registration.sessionE164 = e164
|
|
||||||
}
|
|
||||||
|
|
||||||
return@withContext result
|
|
||||||
}
|
}
|
||||||
|
val result = RegistrationSessionCreationResult.from(registrationSessionResult)
|
||||||
|
if (result is RegistrationSessionCreationResult.Success) {
|
||||||
|
Log.d(TAG, "Updating registration session and E164 in value store.")
|
||||||
|
SignalStore.registration.sessionId = result.sessionId
|
||||||
|
SignalStore.registration.sessionE164 = e164
|
||||||
|
}
|
||||||
|
|
||||||
|
return@withContext result
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates an existing session, if its ID is provided. If the session is expired/invalid, or none is provided, it will attempt to initiate a new session.
|
* Validates an existing session, if its ID is provided. If the session is expired/invalid, or none is provided, it will attempt to initiate a new session.
|
||||||
@@ -379,108 +373,103 @@ object RegistrationRepository {
|
|||||||
/**
|
/**
|
||||||
* Asks the service to send a verification code through one of our supported channels (SMS, phone call).
|
* Asks the service to send a verification code through one of our supported channels (SMS, phone call).
|
||||||
*/
|
*/
|
||||||
suspend fun requestSmsCode(context: Context, sessionId: String, e164: String, password: String, mode: E164VerificationMode): VerificationCodeRequestResult =
|
suspend fun requestSmsCode(context: Context, sessionId: String, e164: String, password: String, mode: E164VerificationMode): VerificationCodeRequestResult = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
|
||||||
|
|
||||||
val codeRequestResult = api.requestSmsVerificationCode(sessionId, Locale.getDefault(), mode.isSmsRetrieverSupported, mode.transport)
|
val codeRequestResult = api.requestSmsVerificationCode(sessionId, Locale.getDefault(), mode.isSmsRetrieverSupported, mode.transport)
|
||||||
|
|
||||||
return@withContext VerificationCodeRequestResult.from(codeRequestResult)
|
return@withContext VerificationCodeRequestResult.from(codeRequestResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submits the user-entered verification code to the service.
|
* Submits the user-entered verification code to the service.
|
||||||
*/
|
*/
|
||||||
suspend fun submitVerificationCode(context: Context, sessionId: String, registrationData: RegistrationData): VerificationCodeRequestResult =
|
suspend fun submitVerificationCode(context: Context, sessionId: String, registrationData: RegistrationData): VerificationCodeRequestResult = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, registrationData.e164, SignalServiceAddress.DEFAULT_DEVICE_ID, registrationData.password).registrationApi
|
||||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, registrationData.e164, SignalServiceAddress.DEFAULT_DEVICE_ID, registrationData.password).registrationApi
|
val result = api.verifyAccount(sessionId = sessionId, verificationCode = registrationData.code)
|
||||||
val result = api.verifyAccount(sessionId = sessionId, verificationCode = registrationData.code)
|
return@withContext VerificationCodeRequestResult.from(result)
|
||||||
return@withContext VerificationCodeRequestResult.from(result)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submits the solved captcha token to the service.
|
* Submits the solved captcha token to the service.
|
||||||
*/
|
*/
|
||||||
suspend fun submitCaptchaToken(context: Context, e164: String, password: String, sessionId: String, captchaToken: String): VerificationCodeRequestResult =
|
suspend fun submitCaptchaToken(context: Context, e164: String, password: String, sessionId: String, captchaToken: String): VerificationCodeRequestResult = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
val captchaSubmissionResult = api.submitCaptchaToken(sessionId = sessionId, captchaToken = captchaToken)
|
||||||
val captchaSubmissionResult = api.submitCaptchaToken(sessionId = sessionId, captchaToken = captchaToken)
|
return@withContext VerificationCodeRequestResult.from(captchaSubmissionResult)
|
||||||
return@withContext VerificationCodeRequestResult.from(captchaSubmissionResult)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun requestAndVerifyPushToken(context: Context, sessionId: String, e164: String, password: String) =
|
suspend fun requestAndVerifyPushToken(context: Context, sessionId: String, e164: String, password: String) = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val fcmToken = getFcmToken(context)
|
||||||
val fcmToken = getFcmToken(context)
|
val accountManager = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password)
|
||||||
val accountManager = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password)
|
val pushChallenge = PushChallengeRequest.getPushChallengeBlocking(accountManager, sessionId, Optional.ofNullable(fcmToken), PUSH_REQUEST_TIMEOUT).orElse(null)
|
||||||
val pushChallenge = PushChallengeRequest.getPushChallengeBlocking(accountManager, sessionId, Optional.ofNullable(fcmToken), PUSH_REQUEST_TIMEOUT).orElse(null)
|
val pushSubmissionResult = accountManager.registrationApi.submitPushChallengeToken(sessionId = sessionId, pushChallengeToken = pushChallenge)
|
||||||
val pushSubmissionResult = accountManager.registrationApi.submitPushChallengeToken(sessionId = sessionId, pushChallengeToken = pushChallenge)
|
return@withContext VerificationCodeRequestResult.from(pushSubmissionResult)
|
||||||
return@withContext VerificationCodeRequestResult.from(pushSubmissionResult)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit the necessary assets as a verified account so that the user can actually use the service.
|
* Submit the necessary assets as a verified account so that the user can actually use the service.
|
||||||
*/
|
*/
|
||||||
suspend fun registerAccount(context: Context, sessionId: String?, registrationData: RegistrationData, pin: String? = null, masterKeyProducer: MasterKeyProducer? = null): RegisterAccountResult =
|
suspend fun registerAccount(context: Context, sessionId: String?, registrationData: RegistrationData, pin: String? = null, masterKeyProducer: MasterKeyProducer? = null): RegisterAccountResult = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
Log.v(TAG, "registerAccount()")
|
||||||
Log.v(TAG, "registerAccount()")
|
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, registrationData.e164, SignalServiceAddress.DEFAULT_DEVICE_ID, registrationData.password).registrationApi
|
||||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, registrationData.e164, SignalServiceAddress.DEFAULT_DEVICE_ID, registrationData.password).registrationApi
|
|
||||||
|
|
||||||
val universalUnidentifiedAccess: Boolean = TextSecurePreferences.isUniversalUnidentifiedAccess(context)
|
val universalUnidentifiedAccess: Boolean = TextSecurePreferences.isUniversalUnidentifiedAccess(context)
|
||||||
val unidentifiedAccessKey: ByteArray = UnidentifiedAccess.deriveAccessKeyFrom(registrationData.profileKey)
|
val unidentifiedAccessKey: ByteArray = UnidentifiedAccess.deriveAccessKeyFrom(registrationData.profileKey)
|
||||||
|
|
||||||
val masterKey: MasterKey?
|
val masterKey: MasterKey?
|
||||||
try {
|
try {
|
||||||
masterKey = masterKeyProducer?.produceMasterKey()
|
masterKey = masterKeyProducer?.produceMasterKey()
|
||||||
} catch (e: SvrNoDataException) {
|
} catch (e: SvrNoDataException) {
|
||||||
return@withContext RegisterAccountResult.SvrNoData(e)
|
return@withContext RegisterAccountResult.SvrNoData(e)
|
||||||
} catch (e: SvrWrongPinException) {
|
} catch (e: SvrWrongPinException) {
|
||||||
return@withContext RegisterAccountResult.SvrWrongPin(e)
|
return@withContext RegisterAccountResult.SvrWrongPin(e)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
return@withContext RegisterAccountResult.UnknownError(e)
|
return@withContext RegisterAccountResult.UnknownError(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
val registrationLock: String? = masterKey?.deriveRegistrationLock()
|
||||||
|
|
||||||
|
val accountAttributes = AccountAttributes(
|
||||||
|
signalingKey = null,
|
||||||
|
registrationId = registrationData.registrationId,
|
||||||
|
fetchesMessages = registrationData.isNotFcm,
|
||||||
|
registrationLock = registrationLock,
|
||||||
|
unidentifiedAccessKey = unidentifiedAccessKey,
|
||||||
|
unrestrictedUnidentifiedAccess = universalUnidentifiedAccess,
|
||||||
|
capabilities = AppCapabilities.getCapabilities(true),
|
||||||
|
discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy.phoneNumberDiscoverabilityMode == PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.DISCOVERABLE,
|
||||||
|
name = null,
|
||||||
|
pniRegistrationId = registrationData.pniRegistrationId,
|
||||||
|
recoveryPassword = registrationData.recoveryPassword
|
||||||
|
)
|
||||||
|
|
||||||
|
SignalStore.account.generateAciIdentityKeyIfNecessary()
|
||||||
|
val aciIdentity: IdentityKeyPair = SignalStore.account.aciIdentityKey
|
||||||
|
|
||||||
|
SignalStore.account.generatePniIdentityKeyIfNecessary()
|
||||||
|
val pniIdentity: IdentityKeyPair = SignalStore.account.pniIdentityKey
|
||||||
|
|
||||||
|
val aciPreKeyCollection = generateSignedAndLastResortPreKeys(aciIdentity, SignalStore.account.aciPreKeys)
|
||||||
|
val pniPreKeyCollection = generateSignedAndLastResortPreKeys(pniIdentity, SignalStore.account.pniPreKeys)
|
||||||
|
|
||||||
|
val result: NetworkResult<AccountRegistrationResult> = api.registerAccount(sessionId, registrationData.recoveryPassword, accountAttributes, aciPreKeyCollection, pniPreKeyCollection, registrationData.fcmToken, true)
|
||||||
|
.map { accountRegistrationResponse: VerifyAccountResponse ->
|
||||||
|
AccountRegistrationResult(
|
||||||
|
uuid = accountRegistrationResponse.uuid,
|
||||||
|
pni = accountRegistrationResponse.pni,
|
||||||
|
storageCapable = accountRegistrationResponse.storageCapable,
|
||||||
|
number = accountRegistrationResponse.number,
|
||||||
|
masterKey = masterKey,
|
||||||
|
pin = pin,
|
||||||
|
aciPreKeyCollection = aciPreKeyCollection,
|
||||||
|
pniPreKeyCollection = pniPreKeyCollection,
|
||||||
|
reRegistration = accountRegistrationResponse.reregistration
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val registrationLock: String? = masterKey?.deriveRegistrationLock()
|
return@withContext RegisterAccountResult.from(result)
|
||||||
|
}
|
||||||
val accountAttributes = AccountAttributes(
|
|
||||||
signalingKey = null,
|
|
||||||
registrationId = registrationData.registrationId,
|
|
||||||
fetchesMessages = registrationData.isNotFcm,
|
|
||||||
registrationLock = registrationLock,
|
|
||||||
unidentifiedAccessKey = unidentifiedAccessKey,
|
|
||||||
unrestrictedUnidentifiedAccess = universalUnidentifiedAccess,
|
|
||||||
capabilities = AppCapabilities.getCapabilities(true),
|
|
||||||
discoverableByPhoneNumber = SignalStore.phoneNumberPrivacy.phoneNumberDiscoverabilityMode == PhoneNumberPrivacyValues.PhoneNumberDiscoverabilityMode.DISCOVERABLE,
|
|
||||||
name = null,
|
|
||||||
pniRegistrationId = registrationData.pniRegistrationId,
|
|
||||||
recoveryPassword = registrationData.recoveryPassword
|
|
||||||
)
|
|
||||||
|
|
||||||
SignalStore.account.generateAciIdentityKeyIfNecessary()
|
|
||||||
val aciIdentity: IdentityKeyPair = SignalStore.account.aciIdentityKey
|
|
||||||
|
|
||||||
SignalStore.account.generatePniIdentityKeyIfNecessary()
|
|
||||||
val pniIdentity: IdentityKeyPair = SignalStore.account.pniIdentityKey
|
|
||||||
|
|
||||||
val aciPreKeyCollection = generateSignedAndLastResortPreKeys(aciIdentity, SignalStore.account.aciPreKeys)
|
|
||||||
val pniPreKeyCollection = generateSignedAndLastResortPreKeys(pniIdentity, SignalStore.account.pniPreKeys)
|
|
||||||
|
|
||||||
val result: NetworkResult<AccountRegistrationResult> = api.registerAccount(sessionId, registrationData.recoveryPassword, accountAttributes, aciPreKeyCollection, pniPreKeyCollection, registrationData.fcmToken, true)
|
|
||||||
.map { accountRegistrationResponse: VerifyAccountResponse ->
|
|
||||||
AccountRegistrationResult(
|
|
||||||
uuid = accountRegistrationResponse.uuid,
|
|
||||||
pni = accountRegistrationResponse.pni,
|
|
||||||
storageCapable = accountRegistrationResponse.storageCapable,
|
|
||||||
number = accountRegistrationResponse.number,
|
|
||||||
masterKey = masterKey,
|
|
||||||
pin = pin,
|
|
||||||
aciPreKeyCollection = aciPreKeyCollection,
|
|
||||||
pniPreKeyCollection = pniPreKeyCollection,
|
|
||||||
reRegistration = accountRegistrationResponse.reregistration
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return@withContext RegisterAccountResult.from(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
fun registerAsLinkedDevice(
|
fun registerAsLinkedDevice(
|
||||||
@@ -539,85 +528,83 @@ object RegistrationRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createSessionAndBlockForPushChallenge(accountManager: RegistrationApi, fcmToken: String, mcc: String?, mnc: String?): NetworkResult<RegistrationSessionMetadataResponse> =
|
private suspend fun createSessionAndBlockForPushChallenge(accountManager: RegistrationApi, fcmToken: String, mcc: String?, mnc: String?): NetworkResult<RegistrationSessionMetadataResponse> = withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
// TODO [regv2]: do not use event bus nor latch
|
||||||
// TODO [regv2]: do not use event bus nor latch
|
val subscriber = PushTokenChallengeSubscriber()
|
||||||
val subscriber = PushTokenChallengeSubscriber()
|
val eventBus = EventBus.getDefault()
|
||||||
val eventBus = EventBus.getDefault()
|
eventBus.register(subscriber)
|
||||||
eventBus.register(subscriber)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Log.d(TAG, "Requesting a registration session with FCM token…")
|
Log.d(TAG, "Requesting a registration session with FCM token…")
|
||||||
val sessionCreationResponse = accountManager.createRegistrationSession(fcmToken, mcc, mnc)
|
val sessionCreationResponse = accountManager.createRegistrationSession(fcmToken, mcc, mnc)
|
||||||
if (sessionCreationResponse !is NetworkResult.Success) {
|
if (sessionCreationResponse !is NetworkResult.Success) {
|
||||||
return@withContext sessionCreationResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
val receivedPush = subscriber.latch.await(PUSH_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
|
|
||||||
eventBus.unregister(subscriber)
|
|
||||||
|
|
||||||
if (receivedPush) {
|
|
||||||
val challenge = subscriber.challenge
|
|
||||||
if (challenge != null) {
|
|
||||||
Log.i(TAG, "Push challenge token received.")
|
|
||||||
return@withContext accountManager.submitPushChallengeToken(sessionCreationResponse.result.metadata.id, challenge)
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Push received but challenge token was null.")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "Push challenge timed out.")
|
|
||||||
}
|
|
||||||
Log.i(TAG, "Push challenge unsuccessful. Continuing with session created without one.")
|
|
||||||
return@withContext sessionCreationResponse
|
return@withContext sessionCreationResponse
|
||||||
} catch (ex: Exception) {
|
|
||||||
Log.w(TAG, "Exception caught, but the earlier try block should have caught it?", ex)
|
|
||||||
return@withContext NetworkResult.ApplicationError<RegistrationSessionMetadataResponse>(ex)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun hasValidSvrAuthCredentials(context: Context, e164: String, password: String): BackupAuthCheckResult =
|
val receivedPush = subscriber.latch.await(PUSH_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
withContext(Dispatchers.IO) {
|
eventBus.unregister(subscriber)
|
||||||
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
|
||||||
|
|
||||||
val svr3Result = SignalStore.svr.svr3AuthTokens
|
if (receivedPush) {
|
||||||
?.takeIf { Svr3Migration.shouldReadFromSvr3 }
|
val challenge = subscriber.challenge
|
||||||
?.takeIf { it.isNotEmpty() }
|
if (challenge != null) {
|
||||||
?.toSvrCredentials()
|
Log.i(TAG, "Push challenge token received.")
|
||||||
?.let { authTokens ->
|
return@withContext accountManager.submitPushChallengeToken(sessionCreationResponse.result.metadata.id, challenge)
|
||||||
api
|
} else {
|
||||||
.validateSvr3AuthCredential(e164, authTokens)
|
Log.w(TAG, "Push received but challenge token was null.")
|
||||||
.runIfSuccessful {
|
|
||||||
val removedInvalidTokens = SignalStore.svr.removeSvr3AuthTokens(it.invalid)
|
|
||||||
if (removedInvalidTokens) {
|
|
||||||
BackupManager(context).dataChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.let { BackupAuthCheckResult.fromV3(it) }
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Push challenge timed out.")
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Push challenge unsuccessful. Continuing with session created without one.")
|
||||||
|
return@withContext sessionCreationResponse
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Log.w(TAG, "Exception caught, but the earlier try block should have caught it?", ex)
|
||||||
|
return@withContext NetworkResult.ApplicationError<RegistrationSessionMetadataResponse>(ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (svr3Result is BackupAuthCheckResult.SuccessWithCredentials) {
|
suspend fun hasValidSvrAuthCredentials(context: Context, e164: String, password: String): BackupAuthCheckResult = withContext(Dispatchers.IO) {
|
||||||
Log.d(TAG, "Found valid SVR3 credentials.")
|
val api: RegistrationApi = AccountManagerFactory.getInstance().createUnauthenticated(context, e164, SignalServiceAddress.DEFAULT_DEVICE_ID, password).registrationApi
|
||||||
return@withContext svr3Result
|
|
||||||
|
val svr3Result = SignalStore.svr.svr3AuthTokens
|
||||||
|
?.takeIf { Svr3Migration.shouldReadFromSvr3 }
|
||||||
|
?.takeIf { it.isNotEmpty() }
|
||||||
|
?.toSvrCredentials()
|
||||||
|
?.let { authTokens ->
|
||||||
|
api
|
||||||
|
.validateSvr3AuthCredential(e164, authTokens)
|
||||||
|
.runIfSuccessful {
|
||||||
|
val removedInvalidTokens = SignalStore.svr.removeSvr3AuthTokens(it.invalid)
|
||||||
|
if (removedInvalidTokens) {
|
||||||
|
BackupManager(context).dataChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.let { BackupAuthCheckResult.fromV3(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "No valid SVR3 credentials, looking for SVR2.")
|
if (svr3Result is BackupAuthCheckResult.SuccessWithCredentials) {
|
||||||
|
Log.d(TAG, "Found valid SVR3 credentials.")
|
||||||
return@withContext SignalStore.svr.svr2AuthTokens
|
return@withContext svr3Result
|
||||||
?.takeIf { it.isNotEmpty() }
|
|
||||||
?.toSvrCredentials()
|
|
||||||
?.let { authTokens ->
|
|
||||||
api
|
|
||||||
.validateSvr2AuthCredential(e164, authTokens)
|
|
||||||
.runIfSuccessful {
|
|
||||||
val removedInvalidTokens = SignalStore.svr.removeSvr2AuthTokens(it.invalid)
|
|
||||||
if (removedInvalidTokens) {
|
|
||||||
BackupManager(context).dataChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.let { BackupAuthCheckResult.fromV2(it) }
|
|
||||||
} ?: BackupAuthCheckResult.SuccessWithoutCredentials()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "No valid SVR3 credentials, looking for SVR2.")
|
||||||
|
|
||||||
|
return@withContext SignalStore.svr.svr2AuthTokens
|
||||||
|
?.takeIf { it.isNotEmpty() }
|
||||||
|
?.toSvrCredentials()
|
||||||
|
?.let { authTokens ->
|
||||||
|
api
|
||||||
|
.validateSvr2AuthCredential(e164, authTokens)
|
||||||
|
.runIfSuccessful {
|
||||||
|
val removedInvalidTokens = SignalStore.svr.removeSvr2AuthTokens(it.invalid)
|
||||||
|
if (removedInvalidTokens) {
|
||||||
|
BackupManager(context).dataChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.let { BackupAuthCheckResult.fromV2(it) }
|
||||||
|
} ?: BackupAuthCheckResult.SuccessWithoutCredentials()
|
||||||
|
}
|
||||||
|
|
||||||
/** Converts the basic-auth creds we have locally into username:password pairs that are suitable for handing off to the service. */
|
/** Converts the basic-auth creds we have locally into username:password pairs that are suitable for handing off to the service. */
|
||||||
private fun List<String?>.toSvrCredentials(): List<String> {
|
private fun List<String?>.toSvrCredentials(): List<String> {
|
||||||
return this
|
return this
|
||||||
|
|||||||
@@ -102,7 +102,9 @@ class ContactRecordProcessor(
|
|||||||
if (!hasAci && !hasPni) {
|
if (!hasAci && !hasPni) {
|
||||||
Log.w(TAG, "Found a ContactRecord with neither an ACI nor a PNI -- marking as invalid.")
|
Log.w(TAG, "Found a ContactRecord with neither an ACI nor a PNI -- marking as invalid.")
|
||||||
return true
|
return true
|
||||||
} else if (selfAci != null && selfAci == remote.proto.signalAci ||
|
} else if (
|
||||||
|
selfAci != null &&
|
||||||
|
selfAci == remote.proto.signalAci ||
|
||||||
(selfPni != null && selfPni == remote.proto.signalPni) ||
|
(selfPni != null && selfPni == remote.proto.signalPni) ||
|
||||||
(selfE164 != null && remote.proto.e164.isNotBlank() && remote.proto.e164 == selfE164)
|
(selfE164 != null && remote.proto.e164.isNotBlank() && remote.proto.e164 == selfE164)
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -309,7 +309,8 @@ class FullSignalAudioManager(context: Context, eventListener: EventListener?) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
val needBluetoothAudioStart = signalBluetoothManager.state == SignalBluetoothManager.State.AVAILABLE &&
|
val needBluetoothAudioStart = signalBluetoothManager.state == SignalBluetoothManager.State.AVAILABLE &&
|
||||||
(userSelectedAudioDevice == AudioDevice.NONE || userSelectedAudioDevice == AudioDevice.BLUETOOTH || autoSwitchToBluetooth) && !androidAudioManager.isBluetoothScoOn
|
(userSelectedAudioDevice == AudioDevice.NONE || userSelectedAudioDevice == AudioDevice.BLUETOOTH || autoSwitchToBluetooth) &&
|
||||||
|
!androidAudioManager.isBluetoothScoOn
|
||||||
|
|
||||||
val needBluetoothAudioStop = (signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTED || signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTING) &&
|
val needBluetoothAudioStop = (signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTED || signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTING) &&
|
||||||
(userSelectedAudioDevice != AudioDevice.NONE && userSelectedAudioDevice != AudioDevice.BLUETOOTH)
|
(userSelectedAudioDevice != AudioDevice.NONE && userSelectedAudioDevice != AudioDevice.BLUETOOTH)
|
||||||
|
|||||||
@@ -171,9 +171,8 @@ class EmojiJsonParserTest {
|
|||||||
|
|
||||||
private fun uriFactory(sprite: String, format: String) = Uri.parse("file:///$sprite")
|
private fun uriFactory(sprite: String, format: String) = Uri.parse("file:///$sprite")
|
||||||
|
|
||||||
private fun EmojiPageModel.isSameAs(other: EmojiPageModel) =
|
private fun EmojiPageModel.isSameAs(other: EmojiPageModel) = this.javaClass == other.javaClass &&
|
||||||
this.javaClass == other.javaClass &&
|
this.emoji == other.emoji &&
|
||||||
this.emoji == other.emoji &&
|
this.iconAttr == other.iconAttr &&
|
||||||
this.iconAttr == other.iconAttr &&
|
this.spriteUri == other.spriteUri
|
||||||
this.spriteUri == other.spriteUri
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,5 @@ class GiphyMp4PlaybackControllerRangeComparatorTest {
|
|||||||
Assert.assertArrayEquals(expected, sorted)
|
Assert.assertArrayEquals(expected, sorted)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createComparator(start: Int, end: Int): GiphyMp4PlaybackController.RangeComparator =
|
private fun createComparator(start: Int, end: Int): GiphyMp4PlaybackController.RangeComparator = GiphyMp4PlaybackController.RangeComparator(start, end)
|
||||||
GiphyMp4PlaybackController.RangeComparator(start, end)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ktlint {
|
ktlint {
|
||||||
version.set("1.2.1")
|
version.set("1.5.0")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ kotlin {
|
|||||||
// NOTE: For now, in order to run ktlint on this project, you have to manually run ./gradlew :build-logic:tools:ktlintFormat
|
// NOTE: For now, in order to run ktlint on this project, you have to manually run ./gradlew :build-logic:tools:ktlintFormat
|
||||||
// Gotta figure out how to get it auto-included in the normal ./gradlew ktlintFormat
|
// Gotta figure out how to get it auto-included in the normal ./gradlew ktlintFormat
|
||||||
ktlint {
|
ktlint {
|
||||||
version.set("1.2.1")
|
version.set("1.5.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
@@ -39,13 +39,12 @@ object IconButtons {
|
|||||||
disabledContainerColor: Color = Color.Transparent,
|
disabledContainerColor: Color = Color.Transparent,
|
||||||
disabledContentColor: Color =
|
disabledContentColor: Color =
|
||||||
contentColor.copy(alpha = 0.38f)
|
contentColor.copy(alpha = 0.38f)
|
||||||
): IconButtonColors =
|
): IconButtonColors = IconButtonColors(
|
||||||
IconButtonColors(
|
containerColor = containerColor,
|
||||||
containerColor = containerColor,
|
contentColor = contentColor,
|
||||||
contentColor = contentColor,
|
disabledContainerColor = disabledContainerColor,
|
||||||
disabledContainerColor = disabledContainerColor,
|
disabledContentColor = disabledContentColor
|
||||||
disabledContentColor = disabledContentColor
|
)
|
||||||
)
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun iconToggleButtonColors(
|
fun iconToggleButtonColors(
|
||||||
@@ -56,15 +55,14 @@ object IconButtons {
|
|||||||
contentColor.copy(alpha = 0.38f),
|
contentColor.copy(alpha = 0.38f),
|
||||||
checkedContainerColor: Color = Color.Transparent,
|
checkedContainerColor: Color = Color.Transparent,
|
||||||
checkedContentColor: Color = MaterialTheme.colorScheme.primary
|
checkedContentColor: Color = MaterialTheme.colorScheme.primary
|
||||||
): IconToggleButtonColors =
|
): IconToggleButtonColors = IconToggleButtonColors(
|
||||||
IconToggleButtonColors(
|
containerColor = containerColor,
|
||||||
containerColor = containerColor,
|
contentColor = contentColor,
|
||||||
contentColor = contentColor,
|
disabledContainerColor = disabledContainerColor,
|
||||||
disabledContainerColor = disabledContainerColor,
|
disabledContentColor = disabledContentColor,
|
||||||
disabledContentColor = disabledContentColor,
|
checkedContainerColor = checkedContainerColor,
|
||||||
checkedContainerColor = checkedContainerColor,
|
checkedContentColor = checkedContentColor
|
||||||
checkedContentColor = checkedContentColor
|
)
|
||||||
)
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun IconButton(
|
fun IconButton(
|
||||||
|
|||||||
@@ -127,5 +127,4 @@ suspend fun AwaitPointerEventScope.awaitLongPressOrCancellation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PointerEvent.isPointerUp(pointerId: PointerId): Boolean =
|
private fun PointerEvent.isPointerUp(pointerId: PointerId): Boolean = changes.fastFirstOrNull { it.id == pointerId }?.pressed != true
|
||||||
changes.fastFirstOrNull { it.id == pointerId }?.pressed != true
|
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ class ResultEventBus {
|
|||||||
/**
|
/**
|
||||||
* Provides a flow for the given resultKey.
|
* Provides a flow for the given resultKey.
|
||||||
*/
|
*/
|
||||||
inline fun <reified T> getResultFlow(resultKey: String = T::class.toString()) =
|
inline fun <reified T> getResultFlow(resultKey: String = T::class.toString()) = channelMap[resultKey]?.receiveAsFlow()
|
||||||
channelMap[resultKey]?.receiveAsFlow()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a result into the channel associated with the given resultKey.
|
* Sends a result into the channel associated with the given resultKey.
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ fun setupWebView(
|
|||||||
webview.evaluateJavascript("editor.setValue($originalContent, -1);", null)
|
webview.evaluateJavascript("editor.setValue($originalContent, -1);", null)
|
||||||
}
|
}
|
||||||
|
|
||||||
copyButton.setOnClickListener { // In Signal app, use Util.writeTextToClipboard(context, value) instead
|
copyButton.setOnClickListener {
|
||||||
|
// In Signal app, use Util.writeTextToClipboard(context, value) instead
|
||||||
webview.evaluateJavascript("editor.getValue();") { value ->
|
webview.evaluateJavascript("editor.getValue();") { value ->
|
||||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
val clip = ClipData.newPlainText(context.getString(R.string.app_name), value)
|
val clip = ClipData.newPlainText(context.getString(R.string.app_name), value)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ accompanist = "0.28.0"
|
|||||||
nanohttpd = "2.3.1"
|
nanohttpd = "2.3.1"
|
||||||
navigation-safe-args-gradle-plugin = "2.8.5"
|
navigation-safe-args-gradle-plugin = "2.8.5"
|
||||||
protobuf-gradle-plugin = "0.9.0"
|
protobuf-gradle-plugin = "0.9.0"
|
||||||
ktlint = "12.1.1"
|
ktlint = "14.0.1"
|
||||||
ui-test-junit4 = "1.9.4"
|
ui-test-junit4 = "1.9.4"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -69,7 +69,7 @@ afterEvaluate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ktlint {
|
ktlint {
|
||||||
version.set("1.2.1")
|
version.set("1.5.0")
|
||||||
|
|
||||||
filter {
|
filter {
|
||||||
exclude { entry ->
|
exclude { entry ->
|
||||||
|
|||||||
Reference in New Issue
Block a user