Update to RingRTC v2.39.0

Co-authored-by: Alex Hart <alex@signal.org>
This commit is contained in:
Jim Gustafson
2024-03-04 10:21:47 -08:00
committed by Alex Hart
parent 4035932340
commit 690608cdf3
15 changed files with 127 additions and 45 deletions

View File

@@ -48,18 +48,25 @@ class UpdateCallLinkRepository(
.subscribeOn(Schedulers.io())
}
fun revokeCallLink(credentials: CallLinkCredentials): Single<UpdateCallLinkResult> {
fun deleteCallLink(credentials: CallLinkCredentials): Single<UpdateCallLinkResult> {
return callLinkManager
.updateCallLinkRevoked(credentials, true)
.deleteCallLink(credentials)
.doOnSuccess(updateState(credentials))
.subscribeOn(Schedulers.io())
}
private fun updateState(credentials: CallLinkCredentials): (UpdateCallLinkResult) -> Unit {
return { result ->
if (result is UpdateCallLinkResult.Success) {
SignalDatabase.callLinks.updateCallLinkState(credentials.roomId, result.state)
ApplicationDependencies.getJobManager().add(CallLinkUpdateSendJob(credentials.roomId))
when (result) {
is UpdateCallLinkResult.Update -> {
SignalDatabase.callLinks.updateCallLinkState(credentials.roomId, result.state)
ApplicationDependencies.getJobManager().add(CallLinkUpdateSendJob(credentials.roomId))
}
is UpdateCallLinkResult.Delete -> {
SignalDatabase.callLinks.markRevoked(credentials.roomId)
ApplicationDependencies.getJobManager().add(CallLinkUpdateSendJob(credentials.roomId))
}
else -> {}
}
}
}

View File

@@ -159,7 +159,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
private fun setCallName(callName: String) {
lifecycleDisposable += viewModel.setCallName(callName).subscribeBy(onSuccess = {
if (it !is UpdateCallLinkResult.Success) {
if (it !is UpdateCallLinkResult.Update) {
Log.w(TAG, "Failed to update call link name")
toastFailure()
}
@@ -168,7 +168,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
private fun setApproveAllMembers(approveAllMembers: Boolean) {
lifecycleDisposable += viewModel.setApproveAllMembers(approveAllMembers).subscribeBy(onSuccess = {
if (it !is UpdateCallLinkResult.Success) {
if (it !is UpdateCallLinkResult.Update) {
Log.w(TAG, "Failed to update call link restrictions")
toastFailure()
}
@@ -177,7 +177,7 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
private fun toggleApproveAllMembers() {
lifecycleDisposable += viewModel.toggleApproveAllMembers().subscribeBy(onSuccess = {
if (it !is UpdateCallLinkResult.Success) {
if (it !is UpdateCallLinkResult.Update) {
Log.w(TAG, "Failed to update call link restrictions")
toastFailure()
}

View File

@@ -141,9 +141,9 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback {
override fun onDeleteConfirmed() {
viewModel.setDisplayRevocationDialog(false)
lifecycleDisposable += viewModel.revoke().observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = {
lifecycleDisposable += viewModel.delete().observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = {
when (it) {
is UpdateCallLinkResult.Success -> ActivityCompat.finishAfterTransition(requireActivity())
is UpdateCallLinkResult.Update -> ActivityCompat.finishAfterTransition(requireActivity())
else -> {
Log.w(TAG, "Failed to revoke. $it")
toastFailure()
@@ -158,7 +158,7 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback {
override fun onApproveAllMembersChanged(checked: Boolean) {
lifecycleDisposable += viewModel.setApproveAllMembers(checked).observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = {
if (it !is UpdateCallLinkResult.Success) {
if (it !is UpdateCallLinkResult.Update) {
Log.w(TAG, "Failed to change restrictions. $it")
toastFailure()
}
@@ -167,7 +167,7 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback {
private fun setName(name: String) {
lifecycleDisposable += viewModel.setName(name).observeOn(AndroidSchedulers.mainThread()).subscribeBy(onSuccess = {
if (it !is UpdateCallLinkResult.Success) {
if (it !is UpdateCallLinkResult.Update) {
Log.w(TAG, "Failed to set name. $it")
toastFailure()
}

View File

@@ -71,9 +71,9 @@ class CallLinkDetailsViewModel(
return mutationRepository.setCallName(credentials, name)
}
fun revoke(): Single<UpdateCallLinkResult> {
fun delete(): Single<UpdateCallLinkResult> {
val credentials = _state.value.callLink?.credentials ?: error("User cannot change the name of this call.")
return mutationRepository.revokeCallLink(credentials)
return mutationRepository.deleteCallLink(credentials)
}
class Factory(private val callLinkRoomId: CallLinkRoomId) : ViewModelProvider.Factory {

View File

@@ -101,7 +101,7 @@ class CallLogRepository(
}
SignalDatabase.callLinks.getAllAdminCallLinksExcept(emptySet())
}.flatMap(this::revokeAndCollectResults).map { 0 }.subscribeOn(Schedulers.io())
}.flatMap(this::deleteAndCollectResults).map { 0 }.subscribeOn(Schedulers.io())
}
/**
@@ -117,7 +117,7 @@ class CallLogRepository(
val allCallLinkIds = SignalDatabase.calls.getCallLinkRoomIdsFromCallRowIds(selectedCallRowIds) + selectedRoomIds
SignalDatabase.callLinks.deleteNonAdminCallLinks(allCallLinkIds)
SignalDatabase.callLinks.getAdminCallLinks(allCallLinkIds)
}.flatMap(this::revokeAndCollectResults).subscribeOn(Schedulers.io())
}.flatMap(this::deleteAndCollectResults).subscribeOn(Schedulers.io())
}
/**
@@ -133,16 +133,16 @@ class CallLogRepository(
val allCallLinkIds = SignalDatabase.calls.getCallLinkRoomIdsFromCallRowIds(selectedCallRowIds) + selectedRoomIds
SignalDatabase.callLinks.deleteAllNonAdminCallLinksExcept(allCallLinkIds)
SignalDatabase.callLinks.getAllAdminCallLinksExcept(allCallLinkIds)
}.flatMap(this::revokeAndCollectResults).subscribeOn(Schedulers.io())
}.flatMap(this::deleteAndCollectResults).subscribeOn(Schedulers.io())
}
private fun revokeAndCollectResults(callLinksToRevoke: Set<CallLinkTable.CallLink>): Single<Int> {
private fun deleteAndCollectResults(callLinksToRevoke: Set<CallLinkTable.CallLink>): Single<Int> {
return Single.merge(
callLinksToRevoke.map {
updateCallLinkRepository.revokeCallLink(it.credentials!!)
updateCallLinkRepository.deleteCallLink(it.credentials!!)
}
).reduce(0) { acc, current ->
acc + (if (current is UpdateCallLinkResult.Success) 0 else 1)
acc + (if (current is UpdateCallLinkResult.Update) 0 else 1)
}.doOnTerminate {
SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps()
}.doOnDispose {

View File

@@ -393,7 +393,7 @@ class ControlsAndInfoController(
controlsAndInfoViewModel.setApproveAllMembers(checked)
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(onSuccess = {
if (it !is UpdateCallLinkResult.Success) {
if (it !is UpdateCallLinkResult.Update) {
Log.w(TAG, "Failed to change restrictions. $it")
toastFailure()
}
@@ -419,7 +419,7 @@ class ControlsAndInfoController(
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onSuccess = {
if (it !is UpdateCallLinkResult.Success) {
if (it !is UpdateCallLinkResult.Update) {
Log.w(TAG, "Failed to set name. $it")
toastFailure()
}

View File

@@ -231,6 +231,37 @@ class CallLinkTable(context: Context, databaseHelper: SignalDatabase) : Database
}
}
/**
* Puts the call link into the "revoked" state which will hide it from the UI and
* delete it after a few days.
*/
fun markRevoked(
roomId: CallLinkRoomId
) {
writableDatabase.withinTransaction { db ->
db.update(TABLE_NAME)
.values("$REVOKED" to true)
.where("$ROOM_ID", roomId)
.run()
SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps()
}
}
/**
* Deletes the call link. This should only happen *after* we send out a sync message
* or receive a sync message which deletes the corresponding link.
*/
fun deleteCallLink(
roomId: CallLinkRoomId
) {
writableDatabase.withinTransaction { db ->
db.delete(TABLE_NAME)
.where("$ROOM_ID", roomId)
.run()
}
}
fun deleteNonAdminCallLinks(roomIds: Set<CallLinkRoomId>) {
val queries = SqlUtil.buildCollectionQuery(ROOM_ID, roomIds)

View File

@@ -26,7 +26,8 @@ import java.util.concurrent.TimeUnit
*/
class CallLinkUpdateSendJob private constructor(
parameters: Parameters,
private val callLinkRoomId: CallLinkRoomId
private val callLinkRoomId: CallLinkRoomId,
private val callLinkUpdateType: CallLinkUpdate.Type
) : BaseJob(parameters) {
companion object {
@@ -35,7 +36,8 @@ class CallLinkUpdateSendJob private constructor(
}
constructor(
callLinkRoomId: CallLinkRoomId
callLinkRoomId: CallLinkRoomId,
callLinkUpdateType: CallLinkUpdate.Type = CallLinkUpdate.Type.UPDATE
) : this(
Parameters.Builder()
.setQueue("CallLinkUpdateSendJob")
@@ -43,11 +45,18 @@ class CallLinkUpdateSendJob private constructor(
.setMaxAttempts(Parameters.UNLIMITED)
.addConstraint(NetworkConstraint.KEY)
.build(),
callLinkRoomId
callLinkRoomId,
callLinkUpdateType
)
override fun serialize(): ByteArray = CallLinkUpdateSendJobData.Builder()
.callLinkRoomId(callLinkRoomId.serialize())
.type(
when (callLinkUpdateType) {
CallLinkUpdate.Type.UPDATE -> CallLinkUpdateSendJobData.Type.UPDATE
CallLinkUpdate.Type.DELETE -> CallLinkUpdateSendJobData.Type.DELETE
}
)
.build()
.encode()
@@ -67,10 +76,17 @@ class CallLinkUpdateSendJob private constructor(
return
}
val callLinkUpdate = CallLinkUpdate(rootKey = callLink.credentials.linkKeyBytes.toByteString())
val callLinkUpdate = CallLinkUpdate(
rootKey = callLink.credentials.linkKeyBytes.toByteString(),
type = callLinkUpdateType
)
ApplicationDependencies.getSignalServiceMessageSender()
.sendSyncMessage(SignalServiceSyncMessage.forCallLinkUpdate(callLinkUpdate), Optional.empty())
if (callLinkUpdateType == CallLinkUpdate.Type.DELETE) {
SignalDatabase.callLinks.deleteCallLink(callLinkRoomId)
}
}
override fun onShouldRetry(e: Exception): Boolean {
@@ -83,9 +99,16 @@ class CallLinkUpdateSendJob private constructor(
class Factory : Job.Factory<CallLinkUpdateSendJob> {
override fun create(parameters: Parameters, serializedData: ByteArray?): CallLinkUpdateSendJob {
val jobData = CallLinkUpdateSendJobData.ADAPTER.decode(serializedData!!)
val type: CallLinkUpdate.Type = when (jobData.type) {
CallLinkUpdateSendJobData.Type.UPDATE, null -> CallLinkUpdate.Type.UPDATE
CallLinkUpdateSendJobData.Type.DELETE -> CallLinkUpdate.Type.DELETE
}
return CallLinkUpdateSendJob(
parameters,
CallLinkRoomId.DatabaseSerializer.deserialize(CallLinkUpdateSendJobData.ADAPTER.decode(serializedData!!).callLinkRoomId)
CallLinkRoomId.DatabaseSerializer.deserialize(jobData.callLinkRoomId),
type
)
}
}

View File

@@ -1223,6 +1223,13 @@ object SyncMessageProcessor {
}
val roomId = CallLinkRoomId.fromCallLinkRootKey(callLinkRootKey)
if (callLinkUpdate.type == CallLinkUpdate.Type.DELETE) {
log(envelopeTimestamp, "Synchronize call link deletion.")
SignalDatabase.callLinks.deleteCallLink(roomId)
return
}
if (SignalDatabase.callLinks.callLinkExists(roomId)) {
log(envelopeTimestamp, "Synchronize call link for a link we already know about. Updating credentials.")
SignalDatabase.callLinks.updateCallLinkCredentials(

View File

@@ -171,7 +171,7 @@ class SignalCallLinkManager(
name
) { result ->
if (result.isSuccess) {
emitter.onSuccess(UpdateCallLinkResult.Success(result.value!!.toAppState()))
emitter.onSuccess(UpdateCallLinkResult.Update(result.value!!.toAppState()))
} else {
emitter.onSuccess(UpdateCallLinkResult.Failure(result.status))
}
@@ -198,7 +198,7 @@ class SignalCallLinkManager(
restrictions
) { result ->
if (result.isSuccess) {
emitter.onSuccess(UpdateCallLinkResult.Success(result.value!!.toAppState()))
emitter.onSuccess(UpdateCallLinkResult.Update(result.value!!.toAppState()))
} else {
emitter.onSuccess(UpdateCallLinkResult.Failure(result.status))
}
@@ -206,9 +206,8 @@ class SignalCallLinkManager(
}
}
fun updateCallLinkRevoked(
credentials: CallLinkCredentials,
revoked: Boolean
fun deleteCallLink(
credentials: CallLinkCredentials
): Single<UpdateCallLinkResult> {
if (credentials.adminPassBytes == null) {
return Single.just(UpdateCallLinkResult.NotAuthorized)
@@ -217,15 +216,14 @@ class SignalCallLinkManager(
return Single.create { emitter ->
val credentialPresentation = requestCallLinkAuthCredentialPresentation(credentials.linkKeyBytes)
callManager.updateCallLinkRevoked(
callManager.deleteCallLink(
SignalStore.internalValues().groupCallingServer(),
credentialPresentation.serialize(),
CallLinkRootKey(credentials.linkKeyBytes),
credentials.adminPassBytes,
revoked
credentials.adminPassBytes
) { result ->
if (result.isSuccess) {
emitter.onSuccess(UpdateCallLinkResult.Success(result.value!!.toAppState()))
if (result.isSuccess && result.value == true) {
emitter.onSuccess(UpdateCallLinkResult.Delete(credentials.roomId))
} else {
emitter.onSuccess(UpdateCallLinkResult.Failure(result.status))
}

View File

@@ -9,10 +9,14 @@ package org.thoughtcrime.securesms.service.webrtc.links
* Result type for call link updates.
*/
sealed interface UpdateCallLinkResult {
data class Success(
data class Update(
val state: SignalCallLinkState
) : UpdateCallLinkResult
data class Delete(
val roomId: CallLinkRoomId
) : UpdateCallLinkResult
data class Failure(
val status: Short
) : UpdateCallLinkResult

View File

@@ -29,7 +29,13 @@ message CallLogEventSendJobData {
}
message CallLinkUpdateSendJobData {
string callLinkRoomId = 1;
enum Type {
UPDATE = 0;
DELETE = 1;
}
string callLinkRoomId = 1;
optional Type type = 2;
}
message AttachmentUploadJobData {

View File

@@ -119,7 +119,7 @@ dependencyResolutionManagement {
library("libsignal-client", "org.signal", "libsignal-client").versionRef("libsignal-client")
library("libsignal-android", "org.signal", "libsignal-android").versionRef("libsignal-client")
library("signal-aesgcmprovider", "org.signal:aesgcmprovider:0.0.3")
library("signal-ringrtc", "org.signal:ringrtc-android:2.38.0")
library("signal-ringrtc", "org.signal:ringrtc-android:2.39.0")
library("signal-android-database-sqlcipher", "org.signal:sqlcipher-android:4.5.4-S2")
// Third Party

View File

@@ -5721,12 +5721,12 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="035ffed2ab5864be068340984d2709597cf065c3fe2688cf68cdfbaf4bdf85e9" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.signal" name="ringrtc-android" version="2.38.0">
<artifact name="ringrtc-android-2.38.0.aar">
<sha256 value="dfff5c7157296d88e5fc1353d0b809dff473dba5df4bd1912ef1f076298ceb72" origin="Generated by Gradle"/>
<component group="org.signal" name="ringrtc-android" version="2.39.0">
<artifact name="ringrtc-android-2.39.0.aar">
<sha256 value="7f12a2e8b229cb88168bfe5cd241047db88cedf36e084ec73e03dcb3abd9a85c" origin="Generated by Gradle"/>
</artifact>
<artifact name="ringrtc-android-2.38.0.module">
<sha256 value="dd6f562de08cb1745a24b5bae40ad31eaa3276d67a64a8f6bc3ee1a36f4754a9" origin="Generated by Gradle"/>
<artifact name="ringrtc-android-2.39.0.module">
<sha256 value="c090a57de1bd55b1530495aef83d8e8971beb6b80029a8230495aad4c4270c8f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.signal" name="sqlcipher-android" version="4.5.4-S2">

View File

@@ -621,8 +621,14 @@ message SyncMessage {
}
message CallLinkUpdate {
enum Type {
UPDATE = 0;
DELETE = 1;
}
optional bytes rootKey = 1;
optional bytes adminPassKey = 2;
optional Type type = 3;
}
message CallLogEvent {