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:
Morgan Pretty 2022-06-21 17:43:27 +10:00
parent 3261f12ea7
commit 153880cf4d
18 changed files with 894 additions and 541 deletions

View File

@ -1150,7 +1150,7 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
OWSAlerts.showErrorAlert(message: "INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE".localized())
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)
}
},

View File

@ -511,6 +511,11 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
currentPlayingInteraction.mutate { $0 = viewModel.id }
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(
mediaUrl: URL(fileURLWithPath: originalFilePath),
audioBehavior: .audioMessagePlayback,
@ -543,7 +548,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
audioPlayer.wrappedValue?.stop()
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
@ -591,7 +601,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
// Clear out the currently playing record
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
guard

View File

@ -200,9 +200,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
DispatchQueue.global(qos: .utility).sync {
let _ = IP2Country.shared.populateCacheIfNeeded()
}
// Get default open group rooms if needed
// OpenGroupManager.getDefaultRoomsIfNeeded() // TODO: Needed???
}
override func viewWillAppear(_ animated: Bool) {
@ -411,13 +408,8 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
switch section.model {
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 }
// Animate the row removal
self?.tableView.beginUpdates()
self?.tableView.deleteRows(at: [indexPath], with: .automatic)
self?.tableView.endUpdates()
}
hide.backgroundColor = Colors.destructive
@ -443,7 +435,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
title: "TXT_DELETE_TITLE".localized(),
style: .destructive
) { _ in
GRDBStorage.shared.write { db in
GRDBStorage.shared.writeAsync { db in
switch cellViewModel.threadVariant {
case .closedGroup:
try MessageSender
@ -477,7 +469,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
"PIN_BUTTON_TEXT".localized()
)
) { _, _ in
GRDBStorage.shared.write { db in
GRDBStorage.shared.writeAsync { db in
try SessionThread
.filter(id: cellViewModel.threadId)
.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()
)
) { _, _ in
GRDBStorage.shared.write { db in
GRDBStorage.shared.writeAsync { db in
try Contact
.filter(id: cellViewModel.threadId)
.updateAll(

View File

@ -73,9 +73,8 @@ public class HomeViewModel {
let hasViewedSeed: Bool = db[.hasViewedSeed]
let userPublicKey: String = getUserHexEncodedPublicKey(db)
let unreadMessageRequestCount: Int = try SessionThread
.unreadMessageRequestsCountQuery(userPublicKey: userPublicKey)
.fetchOne(db)
.defaulting(to: 0)
.unreadMessageRequestsQuery(userPublicKey: userPublicKey)
.fetchCount(db)
let finalUnreadMessageRequestCount: Int = (db[.hasHiddenMessageRequests] ? 0 : unreadMessageRequestCount)
let threads: [SessionThreadViewModel] = try SessionThreadViewModel
.homeQuery(userPublicKey: userPublicKey)

View File

@ -142,10 +142,10 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
}
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 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
// 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)
if thread.variant == .contact {
if isMessageRequest && !db[.hasHiddenMessageRequests] {
let numMessageRequestThreads: Int? = (try? SessionThread
.messageRequestsCountQuery(userPublicKey: userPublicKey)
.fetchOne(db))
let numMessageRequestThreads: Int = (try? SessionThread
.messageRequestsQuery(userPublicKey: userPublicKey, includeNonVisible: true)
.fetchCount(db))
.defaulting(to: 0)
// 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] {
// If there are other interactions on this thread already then don't show the notification

View File

@ -93,7 +93,6 @@ enum MockDataGenerator {
let cgRandomSeed: Int = 2222
let ogRandomSeed: Int = 3333
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 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

View File

@ -21,16 +21,12 @@ public enum SMKLegacy {
public static let threadCollection = "TSThread"
internal static let disappearingMessagesCollection = "OWSDisappearingMessagesConfiguration"
internal static let closedGroupPublicKeyCollection = "SNClosedGroupPublicKeyCollection"
internal static let closedGroupFormationTimestampCollection = "SNClosedGroupFormationTimestampCollection"
internal static let closedGroupZombieMembersCollection = "SNClosedGroupZombieMembersCollection"
internal static let openGroupCollection = "SNOpenGroupCollection"
internal static let openGroupUserCountCollection = "SNOpenGroupUserCountCollection"
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"
internal static let interactionCollection = "TSInteraction"

View File

@ -45,8 +45,6 @@ enum _003_YDBToGRDBMigration: Migration {
var openGroupInfo: [String: SMKLegacy._OpenGroup] = [:]
var openGroupUserCount: [String: Int64] = [:]
var openGroupImage: [String: Data] = [:]
var openGroupLastMessageServerId: [String: Int64] = [:] // Optional
var openGroupLastDeletionServerId: [String: Int64] = [:] // Optional
var interactions: [String: [SMKLegacy._DBInteraction]] = [:]
var attachments: [String: SMKLegacy._Attachment] = [:]
@ -180,8 +178,6 @@ enum _003_YDBToGRDBMigration: Migration {
openGroupInfo[thread.uniqueId] = openGroup
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
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)
@ -787,10 +783,6 @@ enum _003_YDBToGRDBMigration: Migration {
case .mediaSavedNotification: variant = .infoMediaSavedNotification
case .call: variant = .infoCall
case .messageRequestAccepted: variant = .infoMessageRequestAccepted
@unknown default:
SNLog("[Migration Error] Unsupported info message type")
throw StorageError.migrationFailed
}
default:
@ -1100,8 +1092,6 @@ enum _003_YDBToGRDBMigration: Migration {
openGroupInfo = [:]
openGroupUserCount = [:]
openGroupImage = [:]
openGroupLastMessageServerId = [:]
openGroupLastDeletionServerId = [:]
interactions = [:]
attachments = [:]
@ -1507,7 +1497,6 @@ enum _003_YDBToGRDBMigration: Migration {
return (true, nil)
}()
_ = try Attachment(
// 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

View File

@ -38,7 +38,7 @@ public struct Capability: Codable, FetchableRecord, PersistableRecord, TableReco
public init(from valueString: String) {
let maybeValue: Variant? = Variant.allCases.first { $0.rawValue == valueString }
self = (maybeValue ?? .unsupported(valueString))
}
}

View File

@ -169,9 +169,9 @@ public extension SessionThread {
return existingThread
}
func isMessageRequest(_ db: Database) -> Bool {
func isMessageRequest(_ db: Database, includeNonVisible: Bool = false) -> Bool {
return (
shouldBeVisible &&
(includeNonVisible || shouldBeVisible) &&
variant == .contact &&
id != getUserHexEncodedPublicKey(db) && // Note to self
(try? Contact.fetchOne(db, id: id))?.isApproved != true
@ -182,27 +182,27 @@ public extension SessionThread {
// MARK: - Convenience
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 contact: TypedTableAlias<Contact> = TypedTableAlias()
return """
SELECT COUNT(\(thread[.id]))
SELECT \(thread.allColumns())
FROM \(SessionThread.self)
LEFT JOIN \(Contact.self) ON \(contact[.id]) = \(thread[.id])
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 contact: TypedTableAlias<Contact> = TypedTableAlias()
let interaction: TypedTableAlias<Interaction> = TypedTableAlias()
return """
SELECT COUNT(\(thread[.id]))
SELECT \(thread.allColumns())
FROM \(SessionThread.self)
JOIN (
SELECT
@ -225,13 +225,17 @@ public extension SessionThread {
///
/// **Note:** In order to use this filter you **MUST** have a `joining(required/optional:)` to the
/// `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 contact: TypedTableAlias<Contact> = TypedTableAlias()
let shouldBeVisibleSQL: SQL = (includeNonVisible ?
SQL(stringLiteral: "true") :
SQL("\(thread[.shouldBeVisible]) = true")
)
return SQL(
"""
\(thread[.shouldBeVisible]) = true AND
\(shouldBeVisibleSQL) AND
\(SQL("\(thread[.variant]) = \(SessionThread.Variant.contact)")) AND
\(SQL("\(thread[.id]) != \(userPublicKey)")) AND
IFNULL(\(contact[.isApproved]), false) = false

View File

@ -184,6 +184,7 @@ public enum OpenGroupAPI {
_ db: Database,
server: String,
requests: [BatchRequestInfoType],
authenticated: Bool = true,
using dependencies: Dependencies = Dependencies()
) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable?)]> {
let requestBody: BatchRequest = requests.map { $0.toSubRequest() }
@ -198,6 +199,7 @@ public enum OpenGroupAPI {
endpoint: Endpoint.sequence,
body: requestBody
),
authenticated: authenticated,
using: dependencies
)
.decoded(as: responseTypes, on: OpenGroupAPI.workQueue, using: dependencies)
@ -220,7 +222,7 @@ public enum OpenGroupAPI {
/// could return: `{"capabilities": ["sogs", "batch"], "missing": ["magic"]}`
public static func capabilities(
_ db: Database,
on server: String,
server: String,
using dependencies: Dependencies = Dependencies()
) -> Promise<(OnionRequestResponseInfoType, Capabilities)> {
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
public static func rooms(
_ db: Database,
for server: String,
server: String,
using dependencies: Dependencies = Dependencies()
) -> Promise<(OnionRequestResponseInfoType, [Room])> {
return OpenGroupAPI
@ -315,6 +317,7 @@ public enum OpenGroupAPI {
_ db: Database,
for roomToken: String,
on server: String,
authenticated: Bool = true,
using dependencies: Dependencies = Dependencies()
) -> Promise<(capabilities: (info: OnionRequestResponseInfoType, data: Capabilities), room: (info: OnionRequestResponseInfoType, data: Room))> {
let requestResponseType: [BatchRequestInfoType] = [
@ -342,6 +345,7 @@ public enum OpenGroupAPI {
db,
server: server,
requests: requestResponseType,
authenticated: authenticated,
using: dependencies
)
.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>(
_ db: Database,
request: Request<T, Endpoint>,
authenticated: Bool = true,
using dependencies: Dependencies = Dependencies()
) -> Promise<(OnionRequestResponseInfoType, Data?)> {
let urlRequest: URLRequest
@ -1218,6 +1223,11 @@ public enum OpenGroupAPI {
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
guard let signedRequest: URLRequest = sign(db, request: urlRequest, for: request.server, with: publicKey, using: dependencies) else {
return Promise(error: Error.signingFailed)

View File

@ -195,11 +195,16 @@ public final class OpenGroupManager: NSObject {
OpenGroupAPI.workQueue.async {
dependencies.storage
.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
.capabilitiesAndRoom(
db,
for: roomToken,
on: server,
authenticated: false,
using: dependencies
)
}
@ -704,7 +709,7 @@ public final class OpenGroupManager: NSObject {
// Try to retrieve the default rooms 8 times
attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) {
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 }
}

View File

@ -37,7 +37,7 @@ typedef NS_ENUM(NSUInteger, OWSAudioBehavior) {
@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.
@property (nonatomic, weak) id owner;
@property (nonatomic) BOOL isLooping;

File diff suppressed because it is too large Load Diff

View File

@ -113,7 +113,6 @@ class OpenGroupManagerSpec: QuickSpec {
dependencies = OpenGroupManager.OGMDependencies(
cache: Atomic(mockOGMCache),
onionApi: TestCapabilitiesAndRoomApi.self,
identityManager: mockIdentityManager,
generalCache: Atomic(mockGeneralCache),
storage: mockStorage,
sodium: mockSodium,

View File

@ -2,6 +2,8 @@
import Foundation
import Sodium
import GRDB
import SessionUtilitiesKit
import Quick
import Nimble
@ -12,7 +14,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
// MARK: - Spec
override func spec() {
var mockStorage: MockStorage!
var mockStorage: GRDBStorage!
var mockSodium: MockSodium!
var mockBox: MockBox!
var mockGenericHash: MockGenericHash!
@ -23,7 +25,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
describe("a MessageReceiver") {
beforeEach {
mockStorage = MockStorage()
mockStorage = GRDBStorage(customWriter: DatabaseQueue())
mockSodium = MockSodium()
mockBox = MockBox()
mockGenericHash = MockGenericHash()
@ -45,14 +47,10 @@ class MessageReceiverDecryptionSpec: QuickSpec {
nonceGenerator24: mockNonce24Generator
)
mockStorage
.when { $0.getUserED25519KeyPair() }
.thenReturn(
Box.KeyPair(
publicKey: Data(hex: TestConstants.edPublicKey).bytes,
secretKey: Data(hex: TestConstants.edSecretKey).bytes
)
)
mockStorage.write { db in
try Identity(variant: .ed25519PublicKey, data: Data(hex: TestConstants.edPublicKey)).insert(db)
try Identity(variant: .ed25519SecretKey, data: Data(hex: TestConstants.edSecretKey)).insert(db)
}
mockBox
.when {
$0.open(
@ -109,9 +107,9 @@ class MessageReceiverDecryptionSpec: QuickSpec {
"sFMhE5G4PbRtQFey1hsxLl221Qivc3ayaX2Mm/X89Dl8e45BC+Lb/KU9EdesxIK4pVgYXs9XrMtX3v8" +
"dt0eBaXneOBfr7qB8pHwwMZjtkOu1ED07T9nszgbWabBphUfWXe2U9K3PTRisSCI="
)!,
using: try! ECKeyPair(
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
using: Box.KeyPair(
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
),
dependencies: Dependencies()
)
@ -135,14 +133,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
expect {
try MessageReceiver.decryptWithSessionProtocol(
ciphertext: "TestMessage".data(using: .utf8)!,
using: try! ECKeyPair(
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
using: Box.KeyPair(
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
),
dependencies: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if the open message is too short") {
@ -159,14 +157,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
expect {
try MessageReceiver.decryptWithSessionProtocol(
ciphertext: "TestMessage".data(using: .utf8)!,
using: try! ECKeyPair(
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
using: Box.KeyPair(
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
),
dependencies: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if it cannot verify the message") {
@ -177,14 +175,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
expect {
try MessageReceiver.decryptWithSessionProtocol(
ciphertext: "TestMessage".data(using: .utf8)!,
using: try! ECKeyPair(
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
using: Box.KeyPair(
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
),
dependencies: dependencies
)
}
.to(throwError(MessageReceiver.Error.invalidSignature))
.to(throwError(MessageReceiverError.invalidSignature))
}
it("throws an error if it cannot get the senders x25519 public key") {
@ -193,14 +191,14 @@ class MessageReceiverDecryptionSpec: QuickSpec {
expect {
try MessageReceiver.decryptWithSessionProtocol(
ciphertext: "TestMessage".data(using: .utf8)!,
using: try! ECKeyPair(
publicKeyData: Data.data(fromHex: TestConstants.publicKey)!,
privateKeyData: Data.data(fromHex: TestConstants.privateKey)!
using: Box.KeyPair(
publicKey: Data.data(fromHex: TestConstants.publicKey)!.bytes,
secretKey: Data.data(fromHex: TestConstants.privateKey)!.bytes
),
dependencies: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
}
@ -263,7 +261,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if it cannot get the blinded keyPair") {
@ -288,7 +286,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if it cannot get the decryption key") {
@ -321,7 +319,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if the data version is not 0") {
@ -342,7 +340,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if it cannot decrypt the data") {
@ -367,7 +365,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if the inner bytes are too short") {
@ -392,7 +390,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
it("throws an error if it cannot generate the blinding factor") {
@ -417,7 +415,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.invalidSignature))
.to(throwError(MessageReceiverError.invalidSignature))
}
it("throws an error if it cannot generate the combined key") {
@ -442,7 +440,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.invalidSignature))
.to(throwError(MessageReceiverError.invalidSignature))
}
it("throws an error if the combined key does not match kA") {
@ -467,7 +465,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.invalidSignature))
.to(throwError(MessageReceiverError.invalidSignature))
}
it("throws an error if it cannot get the senders x25519 public key") {
@ -492,7 +490,7 @@ class MessageReceiverDecryptionSpec: QuickSpec {
using: dependencies
)
}
.to(throwError(MessageReceiver.Error.decryptionFailed))
.to(throwError(MessageReceiverError.decryptionFailed))
}
}
}

View File

@ -8,8 +8,8 @@ extension OpenGroup: Mocked {
server: any(),
roomToken: any(),
publicKey: TestConstants.publicKey,
name: any(),
isActive: any(),
name: any(),
roomDescription: any(),
imageId: any(),
imageData: any(),
@ -22,7 +22,7 @@ extension OpenGroup: Mocked {
}
extension VisibleMessage: Mocked {
static var mockValue: VisibleMessage = VisibleMessage()
static var mockValue: VisibleMessage = VisibleMessage(text: "")
}
extension BlindedIdMapping: Mocked {

View File

@ -13,7 +13,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol {
guard Date().timeIntervalSince1970 > (thread.mutedUntilTimestamp ?? 0) else { return }
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
// 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)
if thread.variant == .contact {
if isMessageRequest && !db[.hasHiddenMessageRequests] {
let numMessageRequestThreads: Int? = (try? SessionThread
.messageRequestsCountQuery(userPublicKey: userPublicKey)
.fetchOne(db))
let numMessageRequestThreads: Int = (try? SessionThread
.messageRequestsQuery(userPublicKey: userPublicKey, includeNonVisible: true)
.fetchCount(db))
.defaulting(to: 0)
// 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] {
// If there are other interactions on this thread already then don't show the notification