Fixed a few bugs and continued work on fixing unit tests
Fixed a bug where notifications might not work for messages Fixed a bug where auto-playing audio messages wouldn't update the states correctly Fixed a bug where a user wouldn't be able to join an open group with blinding enabled
This commit is contained in:
parent
3261f12ea7
commit
153880cf4d
|
@ -1150,7 +1150,7 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
|
||||||
OWSAlerts.showErrorAlert(message: "INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE".localized())
|
OWSAlerts.showErrorAlert(message: "INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE".localized())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: Looks like the 'play/pause' icon isn't swapping when it auto-plays to the next item)
|
|
||||||
cell.dynamicUpdate(with: cellViewModel, playbackInfo: updatedInfo)
|
cell.dynamicUpdate(with: cellViewModel, playbackInfo: updatedInfo)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -511,6 +511,11 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
||||||
currentPlayingInteraction.mutate { $0 = viewModel.id }
|
currentPlayingInteraction.mutate { $0 = viewModel.id }
|
||||||
|
|
||||||
audioPlayer.mutate { [weak self] player in
|
audioPlayer.mutate { [weak self] player in
|
||||||
|
// Note: We clear the delegate and explicitly set to nil here as when the OWSAudioPlayer
|
||||||
|
// gets deallocated it triggers state changes which cause UI bugs when auto-playing
|
||||||
|
player?.delegate = nil
|
||||||
|
player = nil
|
||||||
|
|
||||||
let audioPlayer: OWSAudioPlayer = OWSAudioPlayer(
|
let audioPlayer: OWSAudioPlayer = OWSAudioPlayer(
|
||||||
mediaUrl: URL(fileURLWithPath: originalFilePath),
|
mediaUrl: URL(fileURLWithPath: originalFilePath),
|
||||||
audioBehavior: .audioMessagePlayback,
|
audioBehavior: .audioMessagePlayback,
|
||||||
|
@ -543,7 +548,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
||||||
audioPlayer.wrappedValue?.stop()
|
audioPlayer.wrappedValue?.stop()
|
||||||
|
|
||||||
currentPlayingInteraction.mutate { $0 = nil }
|
currentPlayingInteraction.mutate { $0 = nil }
|
||||||
audioPlayer.mutate { $0 = nil }
|
audioPlayer.mutate {
|
||||||
|
// Note: We clear the delegate and explicitly set to nil here as when the OWSAudioPlayer
|
||||||
|
// gets deallocated it triggers state changes which cause UI bugs when auto-playing
|
||||||
|
$0?.delegate = nil
|
||||||
|
$0 = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - OWSAudioPlayerDelegate
|
// MARK: - OWSAudioPlayerDelegate
|
||||||
|
@ -591,7 +601,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
||||||
|
|
||||||
// Clear out the currently playing record
|
// Clear out the currently playing record
|
||||||
currentPlayingInteraction.mutate { $0 = nil }
|
currentPlayingInteraction.mutate { $0 = nil }
|
||||||
audioPlayer.mutate { $0 = nil }
|
audioPlayer.mutate {
|
||||||
|
// Note: We clear the delegate and explicitly set to nil here as when the OWSAudioPlayer
|
||||||
|
// gets deallocated it triggers state changes which cause UI bugs when auto-playing
|
||||||
|
$0?.delegate = nil
|
||||||
|
$0 = nil
|
||||||
|
}
|
||||||
|
|
||||||
// If the next interaction is another voice message then autoplay it
|
// If the next interaction is another voice message then autoplay it
|
||||||
guard
|
guard
|
||||||
|
|
|
@ -200,9 +200,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
|
||||||
DispatchQueue.global(qos: .utility).sync {
|
DispatchQueue.global(qos: .utility).sync {
|
||||||
let _ = IP2Country.shared.populateCacheIfNeeded()
|
let _ = IP2Country.shared.populateCacheIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get default open group rooms if needed
|
|
||||||
// OpenGroupManager.getDefaultRoomsIfNeeded() // TODO: Needed???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
@ -411,13 +408,8 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
|
||||||
|
|
||||||
switch section.model {
|
switch section.model {
|
||||||
case .messageRequests:
|
case .messageRequests:
|
||||||
let hide = UITableViewRowAction(style: .destructive, title: "TXT_HIDE_TITLE".localized()) { [weak self] _, _ in
|
let hide = UITableViewRowAction(style: .destructive, title: "TXT_HIDE_TITLE".localized()) { _, _ in
|
||||||
GRDBStorage.shared.write { db in db[.hasHiddenMessageRequests] = true }
|
GRDBStorage.shared.write { db in db[.hasHiddenMessageRequests] = true }
|
||||||
|
|
||||||
// Animate the row removal
|
|
||||||
self?.tableView.beginUpdates()
|
|
||||||
self?.tableView.deleteRows(at: [indexPath], with: .automatic)
|
|
||||||
self?.tableView.endUpdates()
|
|
||||||
}
|
}
|
||||||
hide.backgroundColor = Colors.destructive
|
hide.backgroundColor = Colors.destructive
|
||||||
|
|
||||||
|
@ -443,7 +435,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
|
||||||
title: "TXT_DELETE_TITLE".localized(),
|
title: "TXT_DELETE_TITLE".localized(),
|
||||||
style: .destructive
|
style: .destructive
|
||||||
) { _ in
|
) { _ in
|
||||||
GRDBStorage.shared.write { db in
|
GRDBStorage.shared.writeAsync { db in
|
||||||
switch cellViewModel.threadVariant {
|
switch cellViewModel.threadVariant {
|
||||||
case .closedGroup:
|
case .closedGroup:
|
||||||
try MessageSender
|
try MessageSender
|
||||||
|
@ -477,7 +469,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
|
||||||
"PIN_BUTTON_TEXT".localized()
|
"PIN_BUTTON_TEXT".localized()
|
||||||
)
|
)
|
||||||
) { _, _ in
|
) { _, _ in
|
||||||
GRDBStorage.shared.write { db in
|
GRDBStorage.shared.writeAsync { db in
|
||||||
try SessionThread
|
try SessionThread
|
||||||
.filter(id: cellViewModel.threadId)
|
.filter(id: cellViewModel.threadId)
|
||||||
.updateAll(db, SessionThread.Columns.isPinned.set(to: !cellViewModel.threadIsPinned))
|
.updateAll(db, SessionThread.Columns.isPinned.set(to: !cellViewModel.threadIsPinned))
|
||||||
|
@ -495,7 +487,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
|
||||||
"BLOCK_LIST_BLOCK_BUTTON".localized()
|
"BLOCK_LIST_BLOCK_BUTTON".localized()
|
||||||
)
|
)
|
||||||
) { _, _ in
|
) { _, _ in
|
||||||
GRDBStorage.shared.write { db in
|
GRDBStorage.shared.writeAsync { db in
|
||||||
try Contact
|
try Contact
|
||||||
.filter(id: cellViewModel.threadId)
|
.filter(id: cellViewModel.threadId)
|
||||||
.updateAll(
|
.updateAll(
|
||||||
|
|
|
@ -73,9 +73,8 @@ public class HomeViewModel {
|
||||||
let hasViewedSeed: Bool = db[.hasViewedSeed]
|
let hasViewedSeed: Bool = db[.hasViewedSeed]
|
||||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||||
let unreadMessageRequestCount: Int = try SessionThread
|
let unreadMessageRequestCount: Int = try SessionThread
|
||||||
.unreadMessageRequestsCountQuery(userPublicKey: userPublicKey)
|
.unreadMessageRequestsQuery(userPublicKey: userPublicKey)
|
||||||
.fetchOne(db)
|
.fetchCount(db)
|
||||||
.defaulting(to: 0)
|
|
||||||
let finalUnreadMessageRequestCount: Int = (db[.hasHiddenMessageRequests] ? 0 : unreadMessageRequestCount)
|
let finalUnreadMessageRequestCount: Int = (db[.hasHiddenMessageRequests] ? 0 : unreadMessageRequestCount)
|
||||||
let threads: [SessionThreadViewModel] = try SessionThreadViewModel
|
let threads: [SessionThreadViewModel] = try SessionThreadViewModel
|
||||||
.homeQuery(userPublicKey: userPublicKey)
|
.homeQuery(userPublicKey: userPublicKey)
|
||||||
|
|
|
@ -142,10 +142,10 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func notifyUser(_ db: Database, for interaction: Interaction, in thread: SessionThread, isBackgroundPoll: Bool) {
|
public func notifyUser(_ db: Database, for interaction: Interaction, in thread: SessionThread, isBackgroundPoll: Bool) {
|
||||||
guard Date().timeIntervalSince1970 < (thread.mutedUntilTimestamp ?? 0) else { return }
|
guard Date().timeIntervalSince1970 > (thread.mutedUntilTimestamp ?? 0) else { return }
|
||||||
|
|
||||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||||
let isMessageRequest: Bool = thread.isMessageRequest(db)
|
let isMessageRequest: Bool = thread.isMessageRequest(db, includeNonVisible: true)
|
||||||
|
|
||||||
// If the thread is a message request and the user hasn't hidden message requests then we need
|
// If the thread is a message request and the user hasn't hidden message requests then we need
|
||||||
// to check if this is the only message request thread (group threads can't be message requests
|
// to check if this is the only message request thread (group threads can't be message requests
|
||||||
|
@ -153,13 +153,13 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
|
||||||
// notification regardless of how many message requests there are)
|
// notification regardless of how many message requests there are)
|
||||||
if thread.variant == .contact {
|
if thread.variant == .contact {
|
||||||
if isMessageRequest && !db[.hasHiddenMessageRequests] {
|
if isMessageRequest && !db[.hasHiddenMessageRequests] {
|
||||||
let numMessageRequestThreads: Int? = (try? SessionThread
|
let numMessageRequestThreads: Int = (try? SessionThread
|
||||||
.messageRequestsCountQuery(userPublicKey: userPublicKey)
|
.messageRequestsQuery(userPublicKey: userPublicKey, includeNonVisible: true)
|
||||||
.fetchOne(db))
|
.fetchCount(db))
|
||||||
.defaulting(to: 0)
|
.defaulting(to: 0)
|
||||||
|
|
||||||
// Allow this to show a notification if there are no message requests (ie. this is the first one)
|
// Allow this to show a notification if there are no message requests (ie. this is the first one)
|
||||||
guard (numMessageRequestThreads ?? 0) == 0 else { return }
|
guard numMessageRequestThreads == 0 else { return }
|
||||||
}
|
}
|
||||||
else if isMessageRequest && db[.hasHiddenMessageRequests] {
|
else if isMessageRequest && db[.hasHiddenMessageRequests] {
|
||||||
// If there are other interactions on this thread already then don't show the notification
|
// If there are other interactions on this thread already then don't show the notification
|
||||||
|
|
|
@ -93,7 +93,6 @@ enum MockDataGenerator {
|
||||||
let cgRandomSeed: Int = 2222
|
let cgRandomSeed: Int = 2222
|
||||||
let ogRandomSeed: Int = 3333
|
let ogRandomSeed: Int = 3333
|
||||||
let chunkSize: Int = 1000 // Chunk up the thread writing to prevent memory issues
|
let chunkSize: Int = 1000 // Chunk up the thread writing to prevent memory issues
|
||||||
let openGroupBaseUrl: String = "https://chat.lokinet.dev"
|
|
||||||
let stringContent: [String] = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ".map { String($0) }
|
let stringContent: [String] = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ".map { String($0) }
|
||||||
let wordContent: [String] = ["alias", "consequatur", "aut", "perferendis", "sit", "voluptatem", "accusantium", "doloremque", "aperiam", "eaque", "ipsa", "quae", "ab", "illo", "inventore", "veritatis", "et", "quasi", "architecto", "beatae", "vitae", "dicta", "sunt", "explicabo", "aspernatur", "aut", "odit", "aut", "fugit", "sed", "quia", "consequuntur", "magni", "dolores", "eos", "qui", "ratione", "voluptatem", "sequi", "nesciunt", "neque", "dolorem", "ipsum", "quia", "dolor", "sit", "amet", "consectetur", "adipisci", "velit", "sed", "quia", "non", "numquam", "eius", "modi", "tempora", "incidunt", "ut", "labore", "et", "dolore", "magnam", "aliquam", "quaerat", "voluptatem", "ut", "enim", "ad", "minima", "veniam", "quis", "nostrum", "exercitationem", "ullam", "corporis", "nemo", "enim", "ipsam", "voluptatem", "quia", "voluptas", "sit", "suscipit", "laboriosam", "nisi", "ut", "aliquid", "ex", "ea", "commodi", "consequatur", "quis", "autem", "vel", "eum", "iure", "reprehenderit", "qui", "in", "ea", "voluptate", "velit", "esse", "quam", "nihil", "molestiae", "et", "iusto", "odio", "dignissimos", "ducimus", "qui", "blanditiis", "praesentium", "laudantium", "totam", "rem", "voluptatum", "deleniti", "atque", "corrupti", "quos", "dolores", "et", "quas", "molestias", "excepturi", "sint", "occaecati", "cupiditate", "non", "provident", "sed", "ut", "perspiciatis", "unde", "omnis", "iste", "natus", "error", "similique", "sunt", "in", "culpa", "qui", "officia", "deserunt", "mollitia", "animi", "id", "est", "laborum", "et", "dolorum", "fuga", "et", "harum", "quidem", "rerum", "facilis", "est", "et", "expedita", "distinctio", "nam", "libero", "tempore", "cum", "soluta", "nobis", "est", "eligendi", "optio", "cumque", "nihil", "impedit", "quo", "porro", "quisquam", "est", "qui", "minus", "id", "quod", "maxime", "placeat", "facere", "possimus", "omnis", "voluptas", "assumenda", "est", "omnis", "dolor", "repellendus", "temporibus", "autem", "quibusdam", "et", "aut", "consequatur", "vel", "illum", "qui", "dolorem", "eum", "fugiat", "quo", "voluptas", "nulla", "pariatur", "at", "vero", "eos", "et", "accusamus", "officiis", "debitis", "aut", "rerum", "necessitatibus", "saepe", "eveniet", "ut", "et", "voluptates", "repudiandae", "sint", "et", "molestiae", "non", "recusandae", "itaque", "earum", "rerum", "hic", "tenetur", "a", "sapiente", "delectus", "ut", "aut", "reiciendis", "voluptatibus", "maiores", "doloribus", "asperiores", "repellat"]
|
let wordContent: [String] = ["alias", "consequatur", "aut", "perferendis", "sit", "voluptatem", "accusantium", "doloremque", "aperiam", "eaque", "ipsa", "quae", "ab", "illo", "inventore", "veritatis", "et", "quasi", "architecto", "beatae", "vitae", "dicta", "sunt", "explicabo", "aspernatur", "aut", "odit", "aut", "fugit", "sed", "quia", "consequuntur", "magni", "dolores", "eos", "qui", "ratione", "voluptatem", "sequi", "nesciunt", "neque", "dolorem", "ipsum", "quia", "dolor", "sit", "amet", "consectetur", "adipisci", "velit", "sed", "quia", "non", "numquam", "eius", "modi", "tempora", "incidunt", "ut", "labore", "et", "dolore", "magnam", "aliquam", "quaerat", "voluptatem", "ut", "enim", "ad", "minima", "veniam", "quis", "nostrum", "exercitationem", "ullam", "corporis", "nemo", "enim", "ipsam", "voluptatem", "quia", "voluptas", "sit", "suscipit", "laboriosam", "nisi", "ut", "aliquid", "ex", "ea", "commodi", "consequatur", "quis", "autem", "vel", "eum", "iure", "reprehenderit", "qui", "in", "ea", "voluptate", "velit", "esse", "quam", "nihil", "molestiae", "et", "iusto", "odio", "dignissimos", "ducimus", "qui", "blanditiis", "praesentium", "laudantium", "totam", "rem", "voluptatum", "deleniti", "atque", "corrupti", "quos", "dolores", "et", "quas", "molestias", "excepturi", "sint", "occaecati", "cupiditate", "non", "provident", "sed", "ut", "perspiciatis", "unde", "omnis", "iste", "natus", "error", "similique", "sunt", "in", "culpa", "qui", "officia", "deserunt", "mollitia", "animi", "id", "est", "laborum", "et", "dolorum", "fuga", "et", "harum", "quidem", "rerum", "facilis", "est", "et", "expedita", "distinctio", "nam", "libero", "tempore", "cum", "soluta", "nobis", "est", "eligendi", "optio", "cumque", "nihil", "impedit", "quo", "porro", "quisquam", "est", "qui", "minus", "id", "quod", "maxime", "placeat", "facere", "possimus", "omnis", "voluptas", "assumenda", "est", "omnis", "dolor", "repellendus", "temporibus", "autem", "quibusdam", "et", "aut", "consequatur", "vel", "illum", "qui", "dolorem", "eum", "fugiat", "quo", "voluptas", "nulla", "pariatur", "at", "vero", "eos", "et", "accusamus", "officiis", "debitis", "aut", "rerum", "necessitatibus", "saepe", "eveniet", "ut", "et", "voluptates", "repudiandae", "sint", "et", "molestiae", "non", "recusandae", "itaque", "earum", "rerum", "hic", "tenetur", "a", "sapiente", "delectus", "ut", "aut", "reiciendis", "voluptatibus", "maiores", "doloribus", "asperiores", "repellat"]
|
||||||
let timestampNow: TimeInterval = Date().timeIntervalSince1970
|
let timestampNow: TimeInterval = Date().timeIntervalSince1970
|
||||||
|
|
|
@ -21,16 +21,12 @@ public enum SMKLegacy {
|
||||||
public static let threadCollection = "TSThread"
|
public static let threadCollection = "TSThread"
|
||||||
internal static let disappearingMessagesCollection = "OWSDisappearingMessagesConfiguration"
|
internal static let disappearingMessagesCollection = "OWSDisappearingMessagesConfiguration"
|
||||||
|
|
||||||
internal static let closedGroupPublicKeyCollection = "SNClosedGroupPublicKeyCollection"
|
|
||||||
internal static let closedGroupFormationTimestampCollection = "SNClosedGroupFormationTimestampCollection"
|
internal static let closedGroupFormationTimestampCollection = "SNClosedGroupFormationTimestampCollection"
|
||||||
internal static let closedGroupZombieMembersCollection = "SNClosedGroupZombieMembersCollection"
|
internal static let closedGroupZombieMembersCollection = "SNClosedGroupZombieMembersCollection"
|
||||||
|
|
||||||
internal static let openGroupCollection = "SNOpenGroupCollection"
|
internal static let openGroupCollection = "SNOpenGroupCollection"
|
||||||
internal static let openGroupUserCountCollection = "SNOpenGroupUserCountCollection"
|
internal static let openGroupUserCountCollection = "SNOpenGroupUserCountCollection"
|
||||||
internal static let openGroupImageCollection = "SNOpenGroupImageCollection"
|
internal static let openGroupImageCollection = "SNOpenGroupImageCollection"
|
||||||
internal static let openGroupLastMessageServerIDCollection = "SNLastMessageServerIDCollection"
|
|
||||||
internal static let openGroupLastDeletionServerIDCollection = "SNLastDeletionServerIDCollection"
|
|
||||||
internal static let openGroupServerIdToUniqueIdLookupCollection = "SNOpenGroupServerIdToUniqueIdLookup"
|
|
||||||
|
|
||||||
public static let messageDatabaseViewExtensionName = "TSMessageDatabaseViewExtensionName_Monotonic"
|
public static let messageDatabaseViewExtensionName = "TSMessageDatabaseViewExtensionName_Monotonic"
|
||||||
internal static let interactionCollection = "TSInteraction"
|
internal static let interactionCollection = "TSInteraction"
|
||||||
|
|
|
@ -45,8 +45,6 @@ enum _003_YDBToGRDBMigration: Migration {
|
||||||
var openGroupInfo: [String: SMKLegacy._OpenGroup] = [:]
|
var openGroupInfo: [String: SMKLegacy._OpenGroup] = [:]
|
||||||
var openGroupUserCount: [String: Int64] = [:]
|
var openGroupUserCount: [String: Int64] = [:]
|
||||||
var openGroupImage: [String: Data] = [:]
|
var openGroupImage: [String: Data] = [:]
|
||||||
var openGroupLastMessageServerId: [String: Int64] = [:] // Optional
|
|
||||||
var openGroupLastDeletionServerId: [String: Int64] = [:] // Optional
|
|
||||||
|
|
||||||
var interactions: [String: [SMKLegacy._DBInteraction]] = [:]
|
var interactions: [String: [SMKLegacy._DBInteraction]] = [:]
|
||||||
var attachments: [String: SMKLegacy._Attachment] = [:]
|
var attachments: [String: SMKLegacy._Attachment] = [:]
|
||||||
|
@ -180,8 +178,6 @@ enum _003_YDBToGRDBMigration: Migration {
|
||||||
openGroupInfo[thread.uniqueId] = openGroup
|
openGroupInfo[thread.uniqueId] = openGroup
|
||||||
openGroupUserCount[thread.uniqueId] = ((transaction.object(forKey: openGroup.id, inCollection: SMKLegacy.openGroupUserCountCollection) as? Int64) ?? 0)
|
openGroupUserCount[thread.uniqueId] = ((transaction.object(forKey: openGroup.id, inCollection: SMKLegacy.openGroupUserCountCollection) as? Int64) ?? 0)
|
||||||
openGroupImage[thread.uniqueId] = transaction.object(forKey: openGroup.id, inCollection: SMKLegacy.openGroupImageCollection) as? Data
|
openGroupImage[thread.uniqueId] = transaction.object(forKey: openGroup.id, inCollection: SMKLegacy.openGroupImageCollection) as? Data
|
||||||
openGroupLastMessageServerId[thread.uniqueId] = transaction.object(forKey: openGroup.id, inCollection: SMKLegacy.openGroupLastMessageServerIDCollection) as? Int64
|
|
||||||
openGroupLastDeletionServerId[thread.uniqueId] = transaction.object(forKey: openGroup.id, inCollection: SMKLegacy.openGroupLastDeletionServerIDCollection) as? Int64
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GRDBStorage.shared.update(progress: 0.04, for: self, in: target)
|
GRDBStorage.shared.update(progress: 0.04, for: self, in: target)
|
||||||
|
@ -787,10 +783,6 @@ enum _003_YDBToGRDBMigration: Migration {
|
||||||
case .mediaSavedNotification: variant = .infoMediaSavedNotification
|
case .mediaSavedNotification: variant = .infoMediaSavedNotification
|
||||||
case .call: variant = .infoCall
|
case .call: variant = .infoCall
|
||||||
case .messageRequestAccepted: variant = .infoMessageRequestAccepted
|
case .messageRequestAccepted: variant = .infoMessageRequestAccepted
|
||||||
|
|
||||||
@unknown default:
|
|
||||||
SNLog("[Migration Error] Unsupported info message type")
|
|
||||||
throw StorageError.migrationFailed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1100,8 +1092,6 @@ enum _003_YDBToGRDBMigration: Migration {
|
||||||
openGroupInfo = [:]
|
openGroupInfo = [:]
|
||||||
openGroupUserCount = [:]
|
openGroupUserCount = [:]
|
||||||
openGroupImage = [:]
|
openGroupImage = [:]
|
||||||
openGroupLastMessageServerId = [:]
|
|
||||||
openGroupLastDeletionServerId = [:]
|
|
||||||
|
|
||||||
interactions = [:]
|
interactions = [:]
|
||||||
attachments = [:]
|
attachments = [:]
|
||||||
|
@ -1507,7 +1497,6 @@ enum _003_YDBToGRDBMigration: Migration {
|
||||||
return (true, nil)
|
return (true, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
||||||
_ = try Attachment(
|
_ = try Attachment(
|
||||||
// Note: The legacy attachment object used a UUID string for it's id as well
|
// Note: The legacy attachment object used a UUID string for it's id as well
|
||||||
// and saved files using these id's so just used the existing id so we don't
|
// and saved files using these id's so just used the existing id so we don't
|
||||||
|
|
|
@ -38,7 +38,7 @@ public struct Capability: Codable, FetchableRecord, PersistableRecord, TableReco
|
||||||
|
|
||||||
public init(from valueString: String) {
|
public init(from valueString: String) {
|
||||||
let maybeValue: Variant? = Variant.allCases.first { $0.rawValue == valueString }
|
let maybeValue: Variant? = Variant.allCases.first { $0.rawValue == valueString }
|
||||||
|
|
||||||
self = (maybeValue ?? .unsupported(valueString))
|
self = (maybeValue ?? .unsupported(valueString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,9 +169,9 @@ public extension SessionThread {
|
||||||
return existingThread
|
return existingThread
|
||||||
}
|
}
|
||||||
|
|
||||||
func isMessageRequest(_ db: Database) -> Bool {
|
func isMessageRequest(_ db: Database, includeNonVisible: Bool = false) -> Bool {
|
||||||
return (
|
return (
|
||||||
shouldBeVisible &&
|
(includeNonVisible || shouldBeVisible) &&
|
||||||
variant == .contact &&
|
variant == .contact &&
|
||||||
id != getUserHexEncodedPublicKey(db) && // Note to self
|
id != getUserHexEncodedPublicKey(db) && // Note to self
|
||||||
(try? Contact.fetchOne(db, id: id))?.isApproved != true
|
(try? Contact.fetchOne(db, id: id))?.isApproved != true
|
||||||
|
@ -182,27 +182,27 @@ public extension SessionThread {
|
||||||
// MARK: - Convenience
|
// MARK: - Convenience
|
||||||
|
|
||||||
public extension SessionThread {
|
public extension SessionThread {
|
||||||
static func messageRequestsCountQuery(userPublicKey: String) -> SQLRequest<Int> {
|
static func messageRequestsQuery(userPublicKey: String, includeNonVisible: Bool = false) -> SQLRequest<SessionThread> {
|
||||||
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
||||||
let contact: TypedTableAlias<Contact> = TypedTableAlias()
|
let contact: TypedTableAlias<Contact> = TypedTableAlias()
|
||||||
|
|
||||||
return """
|
return """
|
||||||
SELECT COUNT(\(thread[.id]))
|
SELECT \(thread.allColumns())
|
||||||
FROM \(SessionThread.self)
|
FROM \(SessionThread.self)
|
||||||
LEFT JOIN \(Contact.self) ON \(contact[.id]) = \(thread[.id])
|
LEFT JOIN \(Contact.self) ON \(contact[.id]) = \(thread[.id])
|
||||||
WHERE (
|
WHERE (
|
||||||
\(SessionThread.isMessageRequest(userPublicKey: userPublicKey))
|
\(SessionThread.isMessageRequest(userPublicKey: userPublicKey, includeNonVisible: includeNonVisible))
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
static func unreadMessageRequestsCountQuery(userPublicKey: String) -> SQLRequest<Int> {
|
static func unreadMessageRequestsQuery(userPublicKey: String) -> SQLRequest<SessionThread> {
|
||||||
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
||||||
let contact: TypedTableAlias<Contact> = TypedTableAlias()
|
let contact: TypedTableAlias<Contact> = TypedTableAlias()
|
||||||
let interaction: TypedTableAlias<Interaction> = TypedTableAlias()
|
let interaction: TypedTableAlias<Interaction> = TypedTableAlias()
|
||||||
|
|
||||||
return """
|
return """
|
||||||
SELECT COUNT(\(thread[.id]))
|
SELECT \(thread.allColumns())
|
||||||
FROM \(SessionThread.self)
|
FROM \(SessionThread.self)
|
||||||
JOIN (
|
JOIN (
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -225,13 +225,17 @@ public extension SessionThread {
|
||||||
///
|
///
|
||||||
/// **Note:** In order to use this filter you **MUST** have a `joining(required/optional:)` to the
|
/// **Note:** In order to use this filter you **MUST** have a `joining(required/optional:)` to the
|
||||||
/// `SessionThread.contact` association or it won't work
|
/// `SessionThread.contact` association or it won't work
|
||||||
static func isMessageRequest(userPublicKey: String) -> SQLSpecificExpressible {
|
static func isMessageRequest(userPublicKey: String, includeNonVisible: Bool = false) -> SQLSpecificExpressible {
|
||||||
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
||||||
let contact: TypedTableAlias<Contact> = TypedTableAlias()
|
let contact: TypedTableAlias<Contact> = TypedTableAlias()
|
||||||
|
let shouldBeVisibleSQL: SQL = (includeNonVisible ?
|
||||||
|
SQL(stringLiteral: "true") :
|
||||||
|
SQL("\(thread[.shouldBeVisible]) = true")
|
||||||
|
)
|
||||||
|
|
||||||
return SQL(
|
return SQL(
|
||||||
"""
|
"""
|
||||||
\(thread[.shouldBeVisible]) = true AND
|
\(shouldBeVisibleSQL) AND
|
||||||
\(SQL("\(thread[.variant]) = \(SessionThread.Variant.contact)")) AND
|
\(SQL("\(thread[.variant]) = \(SessionThread.Variant.contact)")) AND
|
||||||
\(SQL("\(thread[.id]) != \(userPublicKey)")) AND
|
\(SQL("\(thread[.id]) != \(userPublicKey)")) AND
|
||||||
IFNULL(\(contact[.isApproved]), false) = false
|
IFNULL(\(contact[.isApproved]), false) = false
|
||||||
|
|
|
@ -184,6 +184,7 @@ public enum OpenGroupAPI {
|
||||||
_ db: Database,
|
_ db: Database,
|
||||||
server: String,
|
server: String,
|
||||||
requests: [BatchRequestInfoType],
|
requests: [BatchRequestInfoType],
|
||||||
|
authenticated: Bool = true,
|
||||||
using dependencies: Dependencies = Dependencies()
|
using dependencies: Dependencies = Dependencies()
|
||||||
) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable?)]> {
|
) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable?)]> {
|
||||||
let requestBody: BatchRequest = requests.map { $0.toSubRequest() }
|
let requestBody: BatchRequest = requests.map { $0.toSubRequest() }
|
||||||
|
@ -198,6 +199,7 @@ public enum OpenGroupAPI {
|
||||||
endpoint: Endpoint.sequence,
|
endpoint: Endpoint.sequence,
|
||||||
body: requestBody
|
body: requestBody
|
||||||
),
|
),
|
||||||
|
authenticated: authenticated,
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
.decoded(as: responseTypes, on: OpenGroupAPI.workQueue, using: dependencies)
|
.decoded(as: responseTypes, on: OpenGroupAPI.workQueue, using: dependencies)
|
||||||
|
@ -220,7 +222,7 @@ public enum OpenGroupAPI {
|
||||||
/// could return: `{"capabilities": ["sogs", "batch"], "missing": ["magic"]}`
|
/// could return: `{"capabilities": ["sogs", "batch"], "missing": ["magic"]}`
|
||||||
public static func capabilities(
|
public static func capabilities(
|
||||||
_ db: Database,
|
_ db: Database,
|
||||||
on server: String,
|
server: String,
|
||||||
using dependencies: Dependencies = Dependencies()
|
using dependencies: Dependencies = Dependencies()
|
||||||
) -> Promise<(OnionRequestResponseInfoType, Capabilities)> {
|
) -> Promise<(OnionRequestResponseInfoType, Capabilities)> {
|
||||||
return OpenGroupAPI
|
return OpenGroupAPI
|
||||||
|
@ -242,7 +244,7 @@ public enum OpenGroupAPI {
|
||||||
/// Rooms to which the user does not have access (e.g. because they are banned, or the room has restricted access permissions) are not included
|
/// Rooms to which the user does not have access (e.g. because they are banned, or the room has restricted access permissions) are not included
|
||||||
public static func rooms(
|
public static func rooms(
|
||||||
_ db: Database,
|
_ db: Database,
|
||||||
for server: String,
|
server: String,
|
||||||
using dependencies: Dependencies = Dependencies()
|
using dependencies: Dependencies = Dependencies()
|
||||||
) -> Promise<(OnionRequestResponseInfoType, [Room])> {
|
) -> Promise<(OnionRequestResponseInfoType, [Room])> {
|
||||||
return OpenGroupAPI
|
return OpenGroupAPI
|
||||||
|
@ -315,6 +317,7 @@ public enum OpenGroupAPI {
|
||||||
_ db: Database,
|
_ db: Database,
|
||||||
for roomToken: String,
|
for roomToken: String,
|
||||||
on server: String,
|
on server: String,
|
||||||
|
authenticated: Bool = true,
|
||||||
using dependencies: Dependencies = Dependencies()
|
using dependencies: Dependencies = Dependencies()
|
||||||
) -> Promise<(capabilities: (info: OnionRequestResponseInfoType, data: Capabilities), room: (info: OnionRequestResponseInfoType, data: Room))> {
|
) -> Promise<(capabilities: (info: OnionRequestResponseInfoType, data: Capabilities), room: (info: OnionRequestResponseInfoType, data: Room))> {
|
||||||
let requestResponseType: [BatchRequestInfoType] = [
|
let requestResponseType: [BatchRequestInfoType] = [
|
||||||
|
@ -342,6 +345,7 @@ public enum OpenGroupAPI {
|
||||||
db,
|
db,
|
||||||
server: server,
|
server: server,
|
||||||
requests: requestResponseType,
|
requests: requestResponseType,
|
||||||
|
authenticated: authenticated,
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
.map { (response: [Endpoint: (OnionRequestResponseInfoType, Codable?)]) -> (capabilities: (OnionRequestResponseInfoType, Capabilities), room: (OnionRequestResponseInfoType, Room)) in
|
.map { (response: [Endpoint: (OnionRequestResponseInfoType, Codable?)]) -> (capabilities: (OnionRequestResponseInfoType, Capabilities), room: (OnionRequestResponseInfoType, Room)) in
|
||||||
|
@ -1199,6 +1203,7 @@ public enum OpenGroupAPI {
|
||||||
private static func send<T: Encodable>(
|
private static func send<T: Encodable>(
|
||||||
_ db: Database,
|
_ db: Database,
|
||||||
request: Request<T, Endpoint>,
|
request: Request<T, Endpoint>,
|
||||||
|
authenticated: Bool = true,
|
||||||
using dependencies: Dependencies = Dependencies()
|
using dependencies: Dependencies = Dependencies()
|
||||||
) -> Promise<(OnionRequestResponseInfoType, Data?)> {
|
) -> Promise<(OnionRequestResponseInfoType, Data?)> {
|
||||||
let urlRequest: URLRequest
|
let urlRequest: URLRequest
|
||||||
|
@ -1218,6 +1223,11 @@ public enum OpenGroupAPI {
|
||||||
|
|
||||||
guard let publicKey: String = maybePublicKey else { return Promise(error: Error.noPublicKey) }
|
guard let publicKey: String = maybePublicKey else { return Promise(error: Error.noPublicKey) }
|
||||||
|
|
||||||
|
// If we don't want to authenticate the request then send it immediately
|
||||||
|
guard authenticated else {
|
||||||
|
return dependencies.onionApi.sendOnionRequest(urlRequest, to: request.server, with: publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to sign the request with the new auth
|
// Attempt to sign the request with the new auth
|
||||||
guard let signedRequest: URLRequest = sign(db, request: urlRequest, for: request.server, with: publicKey, using: dependencies) else {
|
guard let signedRequest: URLRequest = sign(db, request: urlRequest, for: request.server, with: publicKey, using: dependencies) else {
|
||||||
return Promise(error: Error.signingFailed)
|
return Promise(error: Error.signingFailed)
|
||||||
|
|
|
@ -195,11 +195,16 @@ public final class OpenGroupManager: NSObject {
|
||||||
OpenGroupAPI.workQueue.async {
|
OpenGroupAPI.workQueue.async {
|
||||||
dependencies.storage
|
dependencies.storage
|
||||||
.writeAsync { db in
|
.writeAsync { db in
|
||||||
|
// Note: The initial request for room info and it's capabilities should NOT be
|
||||||
|
// authenticated (this is because if the server requires blinding and the auth
|
||||||
|
// headers aren't blinded it will error - these endpoints do support unauthenticated
|
||||||
|
// retrieval so doing so prevents the error)
|
||||||
OpenGroupAPI
|
OpenGroupAPI
|
||||||
.capabilitiesAndRoom(
|
.capabilitiesAndRoom(
|
||||||
db,
|
db,
|
||||||
for: roomToken,
|
for: roomToken,
|
||||||
on: server,
|
on: server,
|
||||||
|
authenticated: false,
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -704,7 +709,7 @@ public final class OpenGroupManager: NSObject {
|
||||||
// Try to retrieve the default rooms 8 times
|
// Try to retrieve the default rooms 8 times
|
||||||
attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) {
|
attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) {
|
||||||
dependencies.storage.read { db in
|
dependencies.storage.read { db in
|
||||||
OpenGroupAPI.rooms(db, for: OpenGroupAPI.defaultServer, using: dependencies)
|
OpenGroupAPI.rooms(db, server: OpenGroupAPI.defaultServer, using: dependencies)
|
||||||
}
|
}
|
||||||
.map { _, data in data }
|
.map { _, data in data }
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ typedef NS_ENUM(NSUInteger, OWSAudioBehavior) {
|
||||||
|
|
||||||
@interface OWSAudioPlayer : NSObject
|
@interface OWSAudioPlayer : NSObject
|
||||||
|
|
||||||
@property (nonatomic, readonly, weak) id<OWSAudioPlayerDelegate> delegate;
|
@property (nonatomic, weak) id<OWSAudioPlayerDelegate> delegate;
|
||||||
// This property can be used to associate instances of the player with view or model objects.
|
// This property can be used to associate instances of the player with view or model objects.
|
||||||
@property (nonatomic, weak) id owner;
|
@property (nonatomic, weak) id owner;
|
||||||
@property (nonatomic) BOOL isLooping;
|
@property (nonatomic) BOOL isLooping;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -113,7 +113,6 @@ class OpenGroupManagerSpec: QuickSpec {
|
||||||
dependencies = OpenGroupManager.OGMDependencies(
|
dependencies = OpenGroupManager.OGMDependencies(
|
||||||
cache: Atomic(mockOGMCache),
|
cache: Atomic(mockOGMCache),
|
||||||
onionApi: TestCapabilitiesAndRoomApi.self,
|
onionApi: TestCapabilitiesAndRoomApi.self,
|
||||||
identityManager: mockIdentityManager,
|
|
||||||
generalCache: Atomic(mockGeneralCache),
|
generalCache: Atomic(mockGeneralCache),
|
||||||
storage: mockStorage,
|
storage: mockStorage,
|
||||||
sodium: mockSodium,
|
sodium: mockSodium,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Sodium
|
import Sodium
|
||||||
|
import GRDB
|
||||||
|
import SessionUtilitiesKit
|
||||||
|
|
||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@ -12,7 +14,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
// MARK: - Spec
|
// MARK: - Spec
|
||||||
|
|
||||||
override func spec() {
|
override func spec() {
|
||||||
var mockStorage: MockStorage!
|
var mockStorage: GRDBStorage!
|
||||||
var mockSodium: MockSodium!
|
var mockSodium: MockSodium!
|
||||||
var mockBox: MockBox!
|
var mockBox: MockBox!
|
||||||
var mockGenericHash: MockGenericHash!
|
var mockGenericHash: MockGenericHash!
|
||||||
|
@ -23,7 +25,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
|
|
||||||
describe("a MessageReceiver") {
|
describe("a MessageReceiver") {
|
||||||
beforeEach {
|
beforeEach {
|
||||||
mockStorage = MockStorage()
|
mockStorage = GRDBStorage(customWriter: DatabaseQueue())
|
||||||
mockSodium = MockSodium()
|
mockSodium = MockSodium()
|
||||||
mockBox = MockBox()
|
mockBox = MockBox()
|
||||||
mockGenericHash = MockGenericHash()
|
mockGenericHash = MockGenericHash()
|
||||||
|
@ -45,14 +47,10 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
nonceGenerator24: mockNonce24Generator
|
nonceGenerator24: mockNonce24Generator
|
||||||
)
|
)
|
||||||
|
|
||||||
mockStorage
|
mockStorage.write { db in
|
||||||
.when { $0.getUserED25519KeyPair() }
|
try Identity(variant: .ed25519PublicKey, data: Data(hex: TestConstants.edPublicKey)).insert(db)
|
||||||
.thenReturn(
|
try Identity(variant: .ed25519SecretKey, data: Data(hex: TestConstants.edSecretKey)).insert(db)
|
||||||
Box.KeyPair(
|
}
|
||||||
publicKey: Data(hex: TestConstants.edPublicKey).bytes,
|
|
||||||
secretKey: Data(hex: TestConstants.edSecretKey).bytes
|
|
||||||
)
|
|
||||||
)
|
|
||||||
mockBox
|
mockBox
|
||||||
.when {
|
.when {
|
||||||
$0.open(
|
$0.open(
|
||||||
|
@ -109,9 +107,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
"sFMhE5G4PbRtQFey1hsxLl221Qivc3ayaX2Mm/X89Dl8e45BC+Lb/KU9EdesxIK4pVgYXs9XrMtX3v8" +
|
"sFMhE5G4PbRtQFey1hsxLl221Qivc3ayaX2Mm/X89Dl8e45BC+Lb/KU9EdesxIK4pVgYXs9XrMtX3v8" +
|
||||||
"dt0eBaXneOBfr7qB8pHwwMZjtkOu1ED07T9nszgbWabBphUfWXe2U9K3PTRisSCI="
|
"dt0eBaXneOBfr7qB8pHwwMZjtkOu1ED07T9nszgbWabBphUfWXe2U9K3PTRisSCI="
|
||||||
)!,
|
)!,
|
||||||
using: try! ECKeyPair(
|
using: Box.KeyPair(
|
||||||
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
|
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
|
||||||
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
|
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
|
||||||
),
|
),
|
||||||
dependencies: Dependencies()
|
dependencies: Dependencies()
|
||||||
)
|
)
|
||||||
|
@ -135,14 +133,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
expect {
|
expect {
|
||||||
try MessageReceiver.decryptWithSessionProtocol(
|
try MessageReceiver.decryptWithSessionProtocol(
|
||||||
ciphertext: "TestMessage".data(using: .utf8)!,
|
ciphertext: "TestMessage".data(using: .utf8)!,
|
||||||
using: try! ECKeyPair(
|
using: Box.KeyPair(
|
||||||
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
|
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
|
||||||
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
|
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
|
||||||
),
|
),
|
||||||
dependencies: dependencies
|
dependencies: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if the open message is too short") {
|
it("throws an error if the open message is too short") {
|
||||||
|
@ -159,14 +157,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
expect {
|
expect {
|
||||||
try MessageReceiver.decryptWithSessionProtocol(
|
try MessageReceiver.decryptWithSessionProtocol(
|
||||||
ciphertext: "TestMessage".data(using: .utf8)!,
|
ciphertext: "TestMessage".data(using: .utf8)!,
|
||||||
using: try! ECKeyPair(
|
using: Box.KeyPair(
|
||||||
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
|
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
|
||||||
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
|
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
|
||||||
),
|
),
|
||||||
dependencies: dependencies
|
dependencies: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot verify the message") {
|
it("throws an error if it cannot verify the message") {
|
||||||
|
@ -177,14 +175,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
expect {
|
expect {
|
||||||
try MessageReceiver.decryptWithSessionProtocol(
|
try MessageReceiver.decryptWithSessionProtocol(
|
||||||
ciphertext: "TestMessage".data(using: .utf8)!,
|
ciphertext: "TestMessage".data(using: .utf8)!,
|
||||||
using: try! ECKeyPair(
|
using: Box.KeyPair(
|
||||||
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
|
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
|
||||||
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
|
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
|
||||||
),
|
),
|
||||||
dependencies: dependencies
|
dependencies: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.invalidSignature))
|
.to(throwError(MessageReceiverError.invalidSignature))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot get the senders x25519 public key") {
|
it("throws an error if it cannot get the senders x25519 public key") {
|
||||||
|
@ -193,14 +191,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
expect {
|
expect {
|
||||||
try MessageReceiver.decryptWithSessionProtocol(
|
try MessageReceiver.decryptWithSessionProtocol(
|
||||||
ciphertext: "TestMessage".data(using: .utf8)!,
|
ciphertext: "TestMessage".data(using: .utf8)!,
|
||||||
using: try! ECKeyPair(
|
using: Box.KeyPair(
|
||||||
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
|
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
|
||||||
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
|
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
|
||||||
),
|
),
|
||||||
dependencies: dependencies
|
dependencies: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +261,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot get the blinded keyPair") {
|
it("throws an error if it cannot get the blinded keyPair") {
|
||||||
|
@ -288,7 +286,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot get the decryption key") {
|
it("throws an error if it cannot get the decryption key") {
|
||||||
|
@ -321,7 +319,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if the data version is not 0") {
|
it("throws an error if the data version is not 0") {
|
||||||
|
@ -342,7 +340,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot decrypt the data") {
|
it("throws an error if it cannot decrypt the data") {
|
||||||
|
@ -367,7 +365,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if the inner bytes are too short") {
|
it("throws an error if the inner bytes are too short") {
|
||||||
|
@ -392,7 +390,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot generate the blinding factor") {
|
it("throws an error if it cannot generate the blinding factor") {
|
||||||
|
@ -417,7 +415,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.invalidSignature))
|
.to(throwError(MessageReceiverError.invalidSignature))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot generate the combined key") {
|
it("throws an error if it cannot generate the combined key") {
|
||||||
|
@ -442,7 +440,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.invalidSignature))
|
.to(throwError(MessageReceiverError.invalidSignature))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if the combined key does not match kA") {
|
it("throws an error if the combined key does not match kA") {
|
||||||
|
@ -467,7 +465,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.invalidSignature))
|
.to(throwError(MessageReceiverError.invalidSignature))
|
||||||
}
|
}
|
||||||
|
|
||||||
it("throws an error if it cannot get the senders x25519 public key") {
|
it("throws an error if it cannot get the senders x25519 public key") {
|
||||||
|
@ -492,7 +490,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
|
||||||
using: dependencies
|
using: dependencies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.to(throwError(MessageReceiver.Error.decryptionFailed))
|
.to(throwError(MessageReceiverError.decryptionFailed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ extension OpenGroup: Mocked {
|
||||||
server: any(),
|
server: any(),
|
||||||
roomToken: any(),
|
roomToken: any(),
|
||||||
publicKey: TestConstants.publicKey,
|
publicKey: TestConstants.publicKey,
|
||||||
name: any(),
|
|
||||||
isActive: any(),
|
isActive: any(),
|
||||||
|
name: any(),
|
||||||
roomDescription: any(),
|
roomDescription: any(),
|
||||||
imageId: any(),
|
imageId: any(),
|
||||||
imageData: any(),
|
imageData: any(),
|
||||||
|
@ -22,7 +22,7 @@ extension OpenGroup: Mocked {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VisibleMessage: Mocked {
|
extension VisibleMessage: Mocked {
|
||||||
static var mockValue: VisibleMessage = VisibleMessage()
|
static var mockValue: VisibleMessage = VisibleMessage(text: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BlindedIdMapping: Mocked {
|
extension BlindedIdMapping: Mocked {
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol {
|
||||||
guard Date().timeIntervalSince1970 > (thread.mutedUntilTimestamp ?? 0) else { return }
|
guard Date().timeIntervalSince1970 > (thread.mutedUntilTimestamp ?? 0) else { return }
|
||||||
|
|
||||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||||
let isMessageRequest: Bool = thread.isMessageRequest(db)
|
let isMessageRequest: Bool = thread.isMessageRequest(db, includeNonVisible: true)
|
||||||
|
|
||||||
// If the thread is a message request and the user hasn't hidden message requests then we need
|
// If the thread is a message request and the user hasn't hidden message requests then we need
|
||||||
// to check if this is the only message request thread (group threads can't be message requests
|
// to check if this is the only message request thread (group threads can't be message requests
|
||||||
|
@ -21,13 +21,13 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol {
|
||||||
// notification regardless of how many message requests there are)
|
// notification regardless of how many message requests there are)
|
||||||
if thread.variant == .contact {
|
if thread.variant == .contact {
|
||||||
if isMessageRequest && !db[.hasHiddenMessageRequests] {
|
if isMessageRequest && !db[.hasHiddenMessageRequests] {
|
||||||
let numMessageRequestThreads: Int? = (try? SessionThread
|
let numMessageRequestThreads: Int = (try? SessionThread
|
||||||
.messageRequestsCountQuery(userPublicKey: userPublicKey)
|
.messageRequestsQuery(userPublicKey: userPublicKey, includeNonVisible: true)
|
||||||
.fetchOne(db))
|
.fetchCount(db))
|
||||||
.defaulting(to: 0)
|
.defaulting(to: 0)
|
||||||
|
|
||||||
// Allow this to show a notification if there are no message requests (ie. this is the first one)
|
// Allow this to show a notification if there are no message requests (ie. this is the first one)
|
||||||
guard (numMessageRequestThreads ?? 0) == 0 else { return }
|
guard numMessageRequestThreads == 0 else { return }
|
||||||
}
|
}
|
||||||
else if isMessageRequest && db[.hasHiddenMessageRequests] {
|
else if isMessageRequest && db[.hasHiddenMessageRequests] {
|
||||||
// If there are other interactions on this thread already then don't show the notification
|
// If there are other interactions on this thread already then don't show the notification
|
||||||
|
|
Loading…
Reference in New Issue