mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 21:15:48 +00:00
@@ -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 -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user