Remove OutgoingEndSessionMessage & associated code

This commit is contained in:
Max Radermacher 2026-04-22 08:59:05 -05:00 committed by GitHub
parent 1caacc0aa8
commit f26cc15de8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 8 additions and 235 deletions

View File

@ -731,7 +731,6 @@
505C2ED42997015800C23FB2 /* LinkDeviceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505C2ED32997015800C23FB2 /* LinkDeviceViewController.swift */; };
505C2ED629971D4E00C23FB2 /* DeviceLimitExceededError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505C2ED529971D4E00C23FB2 /* DeviceLimitExceededError.swift */; };
505C2ED92997422D00C23FB2 /* SelfSignedIdentityTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505C2ED82997422D00C23FB2 /* SelfSignedIdentityTest.swift */; };
505CC1652F229B8400D311CD /* OutgoingEndSessionMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505CC1642F229B8400D311CD /* OutgoingEndSessionMessage.swift */; };
505CC1672F22BC7A00D311CD /* OutgoingPaymentActivationRequestMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505CC1662F22BC7A00D311CD /* OutgoingPaymentActivationRequestMessage.swift */; };
505CC1692F22C2EC00D311CD /* OutgoingPaymentActivationRequestFinishedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505CC1682F22C2EC00D311CD /* OutgoingPaymentActivationRequestFinishedMessage.swift */; };
505F76332BC45C0700B1B51C /* BuildFlags+Generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505F76322BC45C0700B1B51C /* BuildFlags+Generated.swift */; };
@ -1374,7 +1373,6 @@
7254651E2BA012BD00EABFD2 /* AvatarBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FC7EEB265834F30046707A /* AvatarBuilder.swift */; };
7254651F2BA014FC00EABFD2 /* PaymentsCurrenciesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3474C56D26111605006723D2 /* PaymentsCurrenciesImpl.swift */; };
725465202BA016A200EABFD2 /* GroupsV2AvatarDownloadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 347191F823F457BD003A3106 /* GroupsV2AvatarDownloadOperation.swift */; };
725465242BA017D500EABFD2 /* SessionResetJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */; };
725465252BA017EF00EABFD2 /* ThreadUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C686C246B0B100039705A /* ThreadUtil.swift */; };
7254652A2BA01B4800EABFD2 /* PaymentsHelperImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3465F4DA27287858001663AF /* PaymentsHelperImpl.swift */; };
725465382BA01FAA00EABFD2 /* SignalMessagingJobQueues.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9668B34291B088200665298 /* SignalMessagingJobQueues.swift */; };
@ -4785,7 +4783,6 @@
45CADA8A298DD2B4009EBDF5 /* MediaTileScrollFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaTileScrollFlag.swift; sourceTree = "<group>"; };
45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Signal/util/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; };
45D062F427D7F49800BD505E /* OWSContactsManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSContactsManagerTest.swift; sourceTree = "<group>"; };
45D231761DC7E8F10034FA89 /* SessionResetJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionResetJob.swift; sourceTree = "<group>"; };
45D49114296F69AA00B92BB1 /* AllMediaViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllMediaViewController.swift; sourceTree = "<group>"; };
45D9784129F0B50000BBB3C0 /* MediaTileListModeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaTileListModeCell.swift; sourceTree = "<group>"; };
45D9784329F0B51F00BBB3C0 /* AudioCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCell.swift; sourceTree = "<group>"; };
@ -5007,7 +5004,6 @@
505C2ED529971D4E00C23FB2 /* DeviceLimitExceededError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLimitExceededError.swift; sourceTree = "<group>"; };
505C2ED82997422D00C23FB2 /* SelfSignedIdentityTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelfSignedIdentityTest.swift; sourceTree = "<group>"; };
505C2EDA29974D2000C23FB2 /* StorageServiceContactTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageServiceContactTest.swift; sourceTree = "<group>"; };
505CC1642F229B8400D311CD /* OutgoingEndSessionMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingEndSessionMessage.swift; sourceTree = "<group>"; };
505CC1662F22BC7A00D311CD /* OutgoingPaymentActivationRequestMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingPaymentActivationRequestMessage.swift; sourceTree = "<group>"; };
505CC1682F22C2EC00D311CD /* OutgoingPaymentActivationRequestFinishedMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingPaymentActivationRequestFinishedMessage.swift; sourceTree = "<group>"; };
505F76322BC45C0700B1B51C /* BuildFlags+Generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BuildFlags+Generated.swift"; sourceTree = "<group>"; };
@ -13611,7 +13607,6 @@
D925937928B0497900D5D437 /* LocalUserLeaveGroupJob.swift */,
F9C5CAF5289453B200548EEE /* MessageSenderJobQueue.swift */,
F98EA264286A469100791EB4 /* SendGiftBadgeJobQueue.swift */,
45D231761DC7E8F10034FA89 /* SessionResetJob.swift */,
D9668B34291B088200665298 /* SignalMessagingJobQueues.swift */,
);
path = Jobs;
@ -14858,7 +14853,6 @@
50468F2829EE130A00948E02 /* InteractionStore.swift */,
F9C5C8EB289453B100548EEE /* MentionFinder.swift */,
50B74C742F1716F500F59813 /* OutgoingDeleteMessage.swift */,
505CC1642F229B8400D311CD /* OutgoingEndSessionMessage.swift */,
50DE50632F21FE1700F30994 /* OutgoingStaticMessage.swift */,
F9C5C908289453B100548EEE /* OWSDisappearingConfigurationUpdateInfoMessage+SDS.swift */,
F9C5C8F1289453B100548EEE /* OWSDisappearingConfigurationUpdateInfoMessage.h */,
@ -19561,7 +19555,6 @@
D9AA7D6E2D11F08A0014137C /* OutgoingDeviceNameChangeSyncMessage.swift in Sources */,
C13B9BB62A1819C7007F74C4 /* OutgoingEditMessage.swift in Sources */,
C1EAECDF2A1EFC21008A3D58 /* OutgoingEditMessageSyncTranscript.swift in Sources */,
505CC1652F229B8400D311CD /* OutgoingEndSessionMessage.swift in Sources */,
50C55EB82F1B0EFC00BA8309 /* OutgoingFetchLatestSyncMessage.swift in Sources */,
D9AA37A42A8A9A910088EFFB /* OutgoingGroupCallUpdateMessage.swift in Sources */,
F96A534328A1AE7C003262D4 /* OutgoingGroupUpdateMessage.swift in Sources */,
@ -19861,7 +19854,6 @@
50A5AA9B2A7449D000CF2ECC /* ServerReceiptEnvelope.swift in Sources */,
507CD5E529660D5100E47DAC /* ServiceId.swift in Sources */,
F9C5CC96289453B300548EEE /* SessionRecord.pb.swift in Sources */,
725465242BA017D500EABFD2 /* SessionResetJob.swift in Sources */,
D9AE0AD729187A700063488B /* SessionResetJobRecord.swift in Sources */,
501050BB2EB959A4005161CA /* SessionStore.swift in Sources */,
1700E34128BD41150073D949 /* SetAlgebra+SSK.swift in Sources */,

View File

@ -211,8 +211,6 @@ public protocol CVComponentDelegate: AnyObject, AudioMessageViewDelegate, CVPoll
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress)
func didTapCorruptedMessage(_ message: TSErrorMessage)
func didTapSessionRefreshMessage(_ message: TSErrorMessage)
// See: resendGroupUpdate
@ -298,7 +296,6 @@ struct CVMessageAction: Equatable {
case none
case didTapPreviouslyVerifiedIdentityChange(address: SignalServiceAddress)
case didTapUnverifiedIdentityChange(address: SignalServiceAddress)
case didTapCorruptedMessage(errorMessage: TSErrorMessage)
case didTapSessionRefreshMessage(errorMessage: TSErrorMessage)
case didTapResendGroupUpdate(errorMessage: TSErrorMessage)
case didTapGroupMigrationLearnMore
@ -336,8 +333,6 @@ struct CVMessageAction: Equatable {
delegate.didTapPreviouslyVerifiedIdentityChange(address)
case .didTapUnverifiedIdentityChange(let address):
delegate.didTapUnverifiedIdentityChange(address)
case .didTapCorruptedMessage(let errorMessage):
delegate.didTapCorruptedMessage(errorMessage)
case .didTapSessionRefreshMessage(let errorMessage):
delegate.didTapSessionRefreshMessage(errorMessage)
case .didTapResendGroupUpdate(let errorMessage):

View File

@ -1205,18 +1205,14 @@ extension CVComponentSystemMessage {
)
case .wrongTrustedIdentityKey:
return nil
case .invalidKeyException,
.missingKeyId,
.noSession,
.invalidMessage:
return Action(
title: OWSLocalizedString(
"FINGERPRINT_SHRED_KEYMATERIAL_BUTTON",
comment: "Label for button to reset a session.",
),
accessibilityIdentifier: "reset_session",
action: .didTapCorruptedMessage(errorMessage: message),
)
case .invalidKeyException:
return nil
case .missingKeyId:
return nil
case .noSession:
return nil
case .invalidMessage:
return nil
case .sessionRefresh:
return Action(
title: CommonStrings.learnMore,

View File

@ -808,46 +808,6 @@ extension ConversationViewController: CVComponentDelegate {
presentActionSheet(actionSheet)
}
public func didTapCorruptedMessage(_ message: TSErrorMessage) {
AssertIsOnMainThread()
let threadName = SSKEnvironment.shared.databaseStorageRef.read { transaction in
SSKEnvironment.shared.contactManagerRef.displayName(for: self.thread, transaction: transaction)
}
let alertMessage = String.nonPluralLocalizedStringWithFormat(
OWSLocalizedString(
"CORRUPTED_SESSION_DESCRIPTION",
comment: "ActionSheet title",
),
threadName,
)
let alert = ActionSheetController(title: nil, message: alertMessage)
alert.addAction(OWSActionSheets.cancelAction)
alert.addAction(ActionSheetAction(
title: OWSLocalizedString(
"FINGERPRINT_SHRED_KEYMATERIAL_BUTTON",
comment: "",
),
style: .default,
) { [weak self] _ in
guard let self else { return }
guard let contactThread = self.thread as? TSContactThread else {
// Corrupt Message errors only appear in contact threads.
Logger.error("Unexpected request to reset session in group thread.")
return
}
SSKEnvironment.shared.databaseStorageRef.asyncWrite { transaction in
SSKEnvironment.shared.smJobQueuesRef.sessionResetJobQueue.add(contactThread: contactThread, transaction: transaction)
}
})
dismissKeyBoard()
self.presentActionSheet(alert)
}
public func didTapSessionRefreshMessage(_ message: TSErrorMessage) {
dismissKeyBoard()

View File

@ -459,8 +459,6 @@ extension EditHistoryTableSheetViewController: CVComponentDelegate {
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress) {}
func didTapCorruptedMessage(_ message: TSErrorMessage) {}
func didTapSessionRefreshMessage(_ message: TSErrorMessage) {}
func didTapResendGroupUpdateForErrorMessage(_ errorMessage: TSErrorMessage) {}

View File

@ -472,8 +472,6 @@ extension MediaGalleryFileCell: CVComponentDelegate {
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress) {}
func didTapCorruptedMessage(_ message: TSErrorMessage) {}
func didTapSessionRefreshMessage(_ message: TSErrorMessage) {}
func didTapResendGroupUpdateForErrorMessage(_ errorMessage: TSErrorMessage) {}

View File

@ -707,8 +707,6 @@ extension MemberLabelViewController: CVComponentDelegate {
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress) {}
func didTapCorruptedMessage(_ message: TSErrorMessage) {}
func didTapSessionRefreshMessage(_ message: TSErrorMessage) {}
func didTapResendGroupUpdateForErrorMessage(_ errorMessage: TSErrorMessage) {}

View File

@ -1258,9 +1258,6 @@ extension MessageDetailViewController: CVComponentDelegate {
// TODO:
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress) {}
// TODO:
func didTapCorruptedMessage(_ message: TSErrorMessage) {}
// TODO:
func didTapSessionRefreshMessage(_ message: TSErrorMessage) {}

View File

@ -585,8 +585,6 @@ extension PinnedMessagesDetailsViewController: CVComponentDelegate {
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress) {}
func didTapCorruptedMessage(_ message: TSErrorMessage) {}
func didTapSessionRefreshMessage(_ message: TSErrorMessage) {}
func didTapResendGroupUpdateForErrorMessage(_ errorMessage: TSErrorMessage) {}

View File

@ -479,8 +479,6 @@ extension MockConversationView: CVComponentDelegate {
func didTapUnverifiedIdentityChange(_ address: SignalServiceAddress) {}
func didTapCorruptedMessage(_ message: TSErrorMessage) {}
func didTapSessionRefreshMessage(_ message: TSErrorMessage) {}
func didTapResendGroupUpdateForErrorMessage(_ errorMessage: TSErrorMessage) {}

View File

@ -2557,9 +2557,6 @@
/* Indicator that a value has been copied to the clipboard. */
"COPIED_TO_CLIPBOARD" = "Copied to Clipboard";
/* ActionSheet title */
"CORRUPTED_SESSION_DESCRIPTION" = "Resetting your session will allow you to receive future messages from %@, but it will not recover any already corrupted messages.";
/* No comment provided by engineer. */
"COUNTRYCODE_SELECT_TITLE" = "Select Country Code";
@ -3664,9 +3661,6 @@
/* Button that marks user as verified after a successful fingerprint scan. */
"FINGERPRINT_SCAN_VERIFY_BUTTON" = "Mark as Verified";
/* Label for button to reset a session. */
"FINGERPRINT_SHRED_KEYMATERIAL_BUTTON" = "Reset Session";
/* Accessibility label for finishing new group */
"FINISH_GROUP_CREATION_LABEL" = "Finish creating group";

View File

@ -2123,7 +2123,6 @@ extension AppSetup.FinalContinuation {
sskEnvironment.donationReceiptCredentialRedemptionJobQueue.start(appContext: appContext)
sskEnvironment.smJobQueuesRef.incomingContactSyncJobQueue.start(appContext: appContext)
sskEnvironment.smJobQueuesRef.sendGiftBadgeJobQueue.start(appContext: appContext)
sskEnvironment.smJobQueuesRef.sessionResetJobQueue.start(appContext: appContext)
let preKeyManager = dependenciesBridge.preKeyManager
Task {

View File

@ -1,113 +0,0 @@
//
// Copyright 2016 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
public class SessionResetJobQueue {
private let jobQueueRunner: JobQueueRunner<JobRecordFinderImpl<SessionResetJobRecord>, SessionResetJobRunnerFactory>
public init(db: any DB, reachabilityManager: SSKReachabilityManager) {
self.jobQueueRunner = JobQueueRunner(
canExecuteJobsConcurrently: true,
db: db,
jobFinder: JobRecordFinderImpl(db: db),
jobRunnerFactory: SessionResetJobRunnerFactory(),
)
self.jobQueueRunner.listenForReachabilityChanges(reachabilityManager: reachabilityManager)
}
public func start(appContext: AppContext) {
guard appContext.isMainApp else { return }
jobQueueRunner.start(shouldRestartExistingJobs: true)
}
public func add(contactThread: TSContactThread, transaction tx: DBWriteTransaction) {
let jobRecord = SessionResetJobRecord(contactThread: contactThread)
jobRecord.anyInsert(transaction: tx)
tx.addSyncCompletion { self.jobQueueRunner.addPersistedJob(jobRecord) }
}
}
private class SessionResetJobRunnerFactory: JobRunnerFactory {
func buildRunner() -> SessionResetJobRunner { SessionResetJobRunner() }
}
private class SessionResetJobRunner: JobRunner {
private enum Constants {
static let maxRetries: UInt = 10
}
private var hasArchivedAllSessions = false
func runJobAttempt(_ jobRecord: SessionResetJobRecord) async -> JobAttemptResult<Void> {
do {
try await _runJobAttempt(jobRecord)
return .finished(.success(()))
} catch {
return await SSKEnvironment.shared.databaseStorageRef.awaitableWrite { tx in
let result = JobAttemptResult<Void>.performDefaultErrorHandler(
error: error,
jobRecord: jobRecord,
retryLimit: Constants.maxRetries,
tx: tx,
)
if case .finished(.failure) = result {
// Even though this is the failure handler - which means probably the
// recipient didn't receive the message - there's a chance that our send
// did succeed and the server just timed out our response or something.
// Since the cost of sending a future message using a session the recipient
// doesn't have is so high, we archive the session just in case.
Logger.warn("Terminal failure: \(error)")
if let contactThread = try? self.fetchThread(jobRecord: jobRecord, tx: tx) {
self.archiveAllSessions(for: contactThread, tx: tx)
}
}
return result
}
}
}
func didFinishJob(_ jobRecordId: JobRecord.RowId, result: JobResult<Void>) async {}
private func _runJobAttempt(_ jobRecord: SessionResetJobRecord) async throws {
let endSessionMessagePromise = try await SSKEnvironment.shared.databaseStorageRef.awaitableWrite { tx in
let contactThread = try self.fetchThread(jobRecord: jobRecord, tx: tx)
if !self.hasArchivedAllSessions {
self.archiveAllSessions(for: contactThread, tx: tx)
}
let endSessionMessage = OutgoingEndSessionMessage(thread: contactThread, tx: tx)
let preparedMessage = PreparedOutgoingMessage.preprepared(
transientMessageWithoutAttachments: endSessionMessage,
)
return ThreadUtil.enqueueMessagePromise(message: preparedMessage, isHighPriority: true, transaction: tx)
}
self.hasArchivedAllSessions = true
try await endSessionMessagePromise.awaitable()
try await SSKEnvironment.shared.databaseStorageRef.awaitableWrite { tx in
let contactThread = try self.fetchThread(jobRecord: jobRecord, tx: tx)
// Archive the just-created session since the recipient should delete their
// corresponding session upon receiving and decrypting our EndSession
// message. Otherwise if we send another message before them, they won't
// have the session to decrypt it.
self.archiveAllSessions(for: contactThread, tx: tx)
let message = TSInfoMessage(thread: contactThread, messageType: .typeLocalUserEndedSession)
message.anyInsert(transaction: tx)
jobRecord.anyRemove(transaction: tx)
}
}
private func fetchThread(jobRecord: SessionResetJobRecord, tx: DBReadTransaction) throws -> TSContactThread {
let threadId = jobRecord.contactThreadId
guard let contactThread = TSContactThread.fetchContactThreadViaCache(uniqueId: threadId, transaction: tx) else {
throw OWSGenericError("thread for session reset no longer exists")
}
return contactThread
}
private func archiveAllSessions(for contactThread: TSContactThread, tx: DBWriteTransaction) {
let sessionStore = DependenciesBridge.shared.signalProtocolStoreManager.signalProtocolStore(for: .aci).sessionStore
sessionStore.archiveSessions(forAddress: contactThread.contactAddress, tx: tx)
}
}

View File

@ -10,10 +10,8 @@ public class SignalMessagingJobQueues: NSObject {
public init(appReadiness: AppReadiness, db: any DB, reachabilityManager: SSKReachabilityManager) {
incomingContactSyncJobQueue = IncomingContactSyncJobQueue(appReadiness: appReadiness, db: db, reachabilityManager: reachabilityManager)
sendGiftBadgeJobQueue = SendGiftBadgeJobQueue(db: db, reachabilityManager: reachabilityManager)
sessionResetJobQueue = SessionResetJobQueue(db: db, reachabilityManager: reachabilityManager)
}
public let incomingContactSyncJobQueue: IncomingContactSyncJobQueue
public let sendGiftBadgeJobQueue: SendGiftBadgeJobQueue
public let sessionResetJobQueue: SessionResetJobQueue
}

View File

@ -1,35 +0,0 @@
//
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
@objc(OWSEndSessionMessage)
final class OutgoingEndSessionMessage: TransientOutgoingMessage {
override class var supportsSecureCoding: Bool { true }
required init?(coder: NSCoder) {
super.init(coder: coder)
}
init(thread: TSContactThread, tx: DBReadTransaction) {
let messageBuilder = TSOutgoingMessageBuilder.outgoingMessageBuilder(thread: thread)
super.init(
outgoingMessageWith: messageBuilder,
additionalRecipients: [],
explicitRecipients: [],
skippedRecipients: [],
transaction: tx,
)
}
override func dataMessageBuilder(with thread: TSThread, transaction: DBReadTransaction) -> SSKProtoDataMessageBuilder? {
guard let builder = super.dataMessageBuilder(with: thread, transaction: transaction) else {
return nil
}
builder.setTimestamp(self.timestamp)
builder.setFlags(UInt32(SSKProtoDataMessageFlags.endSession.rawValue))
return builder
}
}