Started resolving more TODOs and fixing up unit tests

Updated the Dependencies to lazily create their fallback instances (optimisation to avoid unnecessary initialisations)
Reworked the Atomic type again to have a more consistent behaviour across types
Fixed the build issues with the unit tests (haven't fixed broken tests yet)
pull/592/head
Morgan Pretty 3 years ago
parent 3a75639285
commit bdf5b3bc1b

@ -15,8 +15,8 @@ public final class OpenGroupAPI: NSObject {
// MARK: - Polling State
private static var hasPerformedInitialPoll: AtomicDict<String, Bool> = AtomicDict()
private static var timeSinceLastPoll: AtomicDict<String, TimeInterval> = AtomicDict()
private static var hasPerformedInitialPoll: Atomic<[String: Bool]> = Atomic([:])
private static var timeSinceLastPoll: Atomic<[String: TimeInterval]> = Atomic([:])
private static var lastPollTime: Atomic<TimeInterval> = Atomic(.greatestFiniteMagnitude)
private static let timeSinceLastOpen: Atomic<TimeInterval> = {
@ -27,7 +27,7 @@ public final class OpenGroupAPI: NSObject {
// TODO: Remove these
private static var legacyAuthTokenPromises: AtomicDict<String, Promise<String>> = AtomicDict()
private static var legacyAuthTokenPromises: Atomic<[String: Promise<String>]> = Atomic([:])
private static var legacyHasUpdatedLastOpenDate = false
private static var legacyGroupImagePromises: [String: Promise<Data>] = [:]
@ -43,14 +43,14 @@ public final class OpenGroupAPI: NSObject {
/// - Inbox for the server
public static func poll(_ server: String, using dependencies: Dependencies = Dependencies()) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable?)]> {
// Store a local copy of the cached state for this server
let hadPerformedInitialPoll: Bool = (hasPerformedInitialPoll[server] == true)
let originalTimeSinceLastPoll: TimeInterval = (timeSinceLastPoll[server] ?? min(lastPollTime.wrappedValue, timeSinceLastOpen.wrappedValue))
let hadPerformedInitialPoll: Bool = (hasPerformedInitialPoll.wrappedValue[server] == true)
let originalTimeSinceLastPoll: TimeInterval = (timeSinceLastPoll.wrappedValue[server] ?? min(lastPollTime.wrappedValue, timeSinceLastOpen.wrappedValue))
let maybeLastInboxMessageId: Int64? = dependencies.storage.getOpenGroupInboxLatestMessageId(for: server)
let lastInboxMessageId: Int64 = (maybeLastInboxMessageId ?? 0)
// Update the cached state for this server
hasPerformedInitialPoll.wrappedValue[server] = true
lastPollTime.wrappedValue = min(lastPollTime.wrappedValue, timeSinceLastOpen.wrappedValue)
hasPerformedInitialPoll.mutate { $0[server] = true }
lastPollTime.mutate { $0 = min($0, timeSinceLastOpen.wrappedValue)}
UserDefaults.standard[.lastOpen] = Date()
// Generate the requests
@ -58,13 +58,13 @@ public final class OpenGroupAPI: NSObject {
BatchRequestInfo(
request: Request<NoBody>(
server: server,
endpoint: .capabilities,
queryParameters: [:] // TODO: Add any requirements '.required'
endpoint: .capabilities
),
responseType: Capabilities.self
)
]
.appending(
// Per-room requests
dependencies.storage.getAllOpenGroups().values
.filter { $0.server == server.lowercased() } // Note: The `OpenGroup` type converts to lowercase in init
.flatMap { openGroup -> [BatchRequestInfoType] in

@ -4,42 +4,94 @@ import Foundation
import Sodium
import SessionSnodeKit
// MARK: - Dependencies
extension OpenGroupAPI {
public struct Dependencies {
let api: OnionRequestAPIType.Type
let storage: SessionMessagingKitStorageProtocol
let sodium: SodiumType
let aeadXChaCha20Poly1305Ietf: AeadXChaCha20Poly1305IetfType
let sign: SignType
let genericHash: GenericHashType
let ed25519: Ed25519Type.Type
let nonceGenerator16: NonceGenerator16ByteType
let nonceGenerator24: NonceGenerator24ByteType
let date: Date
public class Dependencies {
private var _api: OnionRequestAPIType.Type?
var api: OnionRequestAPIType.Type {
get { getValueSettingIfNull(&_api) { OnionRequestAPI.self } }
set { _api = newValue }
}
private var _storage: SessionMessagingKitStorageProtocol?
var storage: SessionMessagingKitStorageProtocol {
get { getValueSettingIfNull(&_storage) { SNMessagingKitConfiguration.shared.storage } }
set { _storage = newValue }
}
private var _sodium: SodiumType?
var sodium: SodiumType {
get { getValueSettingIfNull(&_sodium) { Sodium() } }
set { _sodium = newValue }
}
private var _aeadXChaCha20Poly1305Ietf: AeadXChaCha20Poly1305IetfType?
var aeadXChaCha20Poly1305Ietf: AeadXChaCha20Poly1305IetfType {
get { getValueSettingIfNull(&_aeadXChaCha20Poly1305Ietf) { sodium.getAeadXChaCha20Poly1305Ietf() } }
set { _aeadXChaCha20Poly1305Ietf = newValue }
}
private var _sign: SignType?
var sign: SignType {
get { getValueSettingIfNull(&_sign) { sodium.getSign() } }
set { _sign = newValue }
}
private var _genericHash: GenericHashType?
var genericHash: GenericHashType {
get { getValueSettingIfNull(&_genericHash) { sodium.getGenericHash() } }
set { _genericHash = newValue }
}
private var _ed25519: Ed25519Type.Type?
var ed25519: Ed25519Type.Type {
get { getValueSettingIfNull(&_ed25519) { Ed25519.self } }
set { _ed25519 = newValue }
}
private var _nonceGenerator16: NonceGenerator16ByteType?
var nonceGenerator16: NonceGenerator16ByteType {
get { getValueSettingIfNull(&_nonceGenerator16) { NonceGenerator16Byte() } }
set { _nonceGenerator16 = newValue }
}
private var _nonceGenerator24: NonceGenerator24ByteType?
var nonceGenerator24: NonceGenerator24ByteType {
get { getValueSettingIfNull(&_nonceGenerator24) { NonceGenerator24Byte() } }
set { _nonceGenerator24 = newValue }
}
private var _date: Date?
var date: Date {
get { getValueSettingIfNull(&_date) { Date() } }
set { _date = newValue }
}
// MARK: - Initialization
public init(
api: OnionRequestAPIType.Type = OnionRequestAPI.self,
storage: SessionMessagingKitStorageProtocol = SNMessagingKitConfiguration.shared.storage,
// TODO: Shift the next 3 to be abstracted behind a single "signing" class?
sodium: SodiumType = Sodium(),
api: OnionRequestAPIType.Type? = nil,
storage: SessionMessagingKitStorageProtocol? = nil,
sodium: SodiumType? = nil,
aeadXChaCha20Poly1305Ietf: AeadXChaCha20Poly1305IetfType? = nil,
sign: SignType? = nil,
genericHash: GenericHashType? = nil,
ed25519: Ed25519Type.Type = Ed25519.self,
nonceGenerator16: NonceGenerator16ByteType = NonceGenerator16Byte(),
nonceGenerator24: NonceGenerator24ByteType = NonceGenerator24Byte(),
date: Date = Date()
ed25519: Ed25519Type.Type? = nil,
nonceGenerator16: NonceGenerator16ByteType? = nil,
nonceGenerator24: NonceGenerator24ByteType? = nil,
date: Date? = nil
) {
self.api = api
self.storage = storage
self.sodium = sodium
self.aeadXChaCha20Poly1305Ietf = (aeadXChaCha20Poly1305Ietf ?? sodium.getAeadXChaCha20Poly1305Ietf())
self.sign = (sign ?? sodium.getSign())
self.genericHash = (genericHash ?? sodium.getGenericHash())
self.ed25519 = ed25519
self.nonceGenerator16 = nonceGenerator16
self.nonceGenerator24 = nonceGenerator24
self.date = date
_api = api
_storage = storage
_sodium = sodium
_aeadXChaCha20Poly1305Ietf = aeadXChaCha20Poly1305Ietf
_sign = sign
_genericHash = genericHash
_ed25519 = ed25519
_nonceGenerator16 = nonceGenerator16
_nonceGenerator24 = nonceGenerator24
_date = date
}
// MARK: - Convenience
@ -57,17 +109,29 @@ extension OpenGroupAPI {
date: Date? = nil
) -> Dependencies {
return Dependencies(
api: (api ?? self.api),
storage: (storage ?? self.storage),
sodium: (sodium ?? self.sodium),
aeadXChaCha20Poly1305Ietf: (aeadXChaCha20Poly1305Ietf ?? self.aeadXChaCha20Poly1305Ietf),
sign: (sign ?? self.sign),
genericHash: (genericHash ?? self.genericHash),
ed25519: (ed25519 ?? self.ed25519),
nonceGenerator16: (nonceGenerator16 ?? self.nonceGenerator16),
nonceGenerator24: (nonceGenerator24 ?? self.nonceGenerator24),
date: (date ?? self.date)
api: (api ?? self._api),
storage: (storage ?? self._storage),
sodium: (sodium ?? self._sodium),
aeadXChaCha20Poly1305Ietf: (aeadXChaCha20Poly1305Ietf ?? self._aeadXChaCha20Poly1305Ietf),
sign: (sign ?? self._sign),
genericHash: (genericHash ?? self._genericHash),
ed25519: (ed25519 ?? self._ed25519),
nonceGenerator16: (nonceGenerator16 ?? self._nonceGenerator16),
nonceGenerator24: (nonceGenerator24 ?? self._nonceGenerator24),
date: (date ?? self._date)
)
}
}
}
// MARK: - Convenience
fileprivate func getValueSettingIfNull<T>(_ maybeValue: inout T?, _ valueGenerator: () -> T) -> T {
guard let value: T = maybeValue else {
let value: T = valueGenerator()
maybeValue = value
return value
}
return value
}

@ -2,94 +2,45 @@
import Foundation
/// See https://www.donnywals.com/why-your-atomic-property-wrapper-doesnt-work-for-collection-types/
/// for more information about the below types
protocol UnsupportedType {}
extension Array: UnsupportedType {}
extension Set: UnsupportedType {}
extension Dictionary: UnsupportedType {}
// MARK: - Atomic<Value>
/// The `Atomic<Value>` wrapper is a generic wrapper providing a thread-safe way to get and set a value
@propertyWrapper
struct Atomic<Value> {
private let queue: DispatchQueue = DispatchQueue(label: "io.oxen.\(UUID().uuidString)", qos: .utility, attributes: .concurrent, autoreleaseFrequency: .inherit, target: .global())
private var value: Value
init(_ initialValue: Value) {
if initialValue is UnsupportedType { preconditionFailure("Use the appropriate Aromic... type for collections") }
self.value = initialValue
}
var wrappedValue: Value {
get { return queue.sync { return value } }
set { return queue.sync { value = newValue } }
}
}
extension Atomic where Value: CustomDebugStringConvertible {
var debugDescription: String {
return value.debugDescription
}
}
// MARK: - AtomicArray<Value>
/// The `AtomicArray<Value>` wrapper is a generic wrapper providing a thread-safe way to get and set an array or one of it's values
///
/// Note: This is a class rather than a struct as you need to modify a reference rather than a copy for the concurrency to work
/// A write-up on the need for this class and it's approach can be found here:
/// https://www.vadimbulavin.com/swift-atomic-properties-with-property-wrappers/
/// there is also another approach which can be taken but it requires separate types for collections and results in
/// a somewhat inconsistent interface between different `Atomic` wrappers
@propertyWrapper
class AtomicArray<Value>: CustomDebugStringConvertible {
private let queue: DispatchQueue = DispatchQueue(label: "io.oxen.\(UUID().uuidString)", qos: .utility, attributes: .concurrent, autoreleaseFrequency: .inherit, target: .global())
private var value: [Value]
init(_ initialValue: [Value] = []) {
self.value = initialValue
}
var wrappedValue: [Value] {
get { return queue.sync { return value } }
set { return queue.sync { value = newValue } }
}
public class Atomic<Value> {
private let queue: DispatchQueue = DispatchQueue(label: "io.oxen.\(UUID().uuidString)")
private var value: Value
subscript(index: Int) -> Value {
get { queue.sync { value[index] }}
set { queue.async(flags: .barrier) { self.value[index] = newValue } }
/// In order to change the value you **must** use the `mutate` function
public var wrappedValue: Value {
return queue.sync { return value }
}
public var debugDescription: String {
return value.debugDescription
/// For more information see https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#projections
public var projectedValue: Atomic<Value> {
return self
}
}
// MARK: - AtomicDict<Key, Value>
/// The `AtomicDict<Key, Value>` wrapper is a generic wrapper providing a thread-safe way to get and set a dictionaries or one of it's values
///
/// Note: This is a class rather than a struct as you need to modify a reference rather than a copy for the concurrency to work
@propertyWrapper
class AtomicDict<Key: Hashable, Value>: CustomDebugStringConvertible {
private let queue: DispatchQueue = DispatchQueue(label: "io.oxen.\(UUID().uuidString)", qos: .utility, attributes: .concurrent, autoreleaseFrequency: .inherit, target: .global())
private var value: [Key: Value]
// MARK: - Initialization
init(_ initialValue: [Key: Value] = [:]) {
init(_ initialValue: Value) {
self.value = initialValue
}
var wrappedValue: [Key: Value] {
get { return queue.sync { return value } }
set { return queue.sync { value = newValue } }
}
// MARK: - Functions
subscript(key: Key) -> Value? {
get { queue.sync { value[key] }}
set { queue.async(flags: .barrier) { self.value[key] = newValue } }
func mutate(_ mutation: (inout Value) -> Void) {
return queue.sync {
mutation(&value)
}
}
}
extension Atomic where Value: CustomDebugStringConvertible {
var debugDescription: String {
return value.debugDescription
}

@ -21,9 +21,17 @@ class OpenGroupAPITests: XCTestCase {
}
}
struct TestNonceGenerator: NonceGenerator16ByteType {
struct TestNonce16Generator: NonceGenerator16ByteType {
var NonceBytes: Int = 16
func nonce() -> Array<UInt8> { return Data(base64Encoded: "pK6YRtQApl4NhECGizF0Cg==")!.bytes }
}
struct TestNonce24Generator: NonceGenerator24ByteType {
var NonceBytes: Int = 24
func nonce() -> Array<UInt8> { return Data(base64Encoded: "pbTUizreT0sqJ2R2LloseQDyVL2RYztD")!.bytes }
}
class TestApi: OnionRequestAPIType {
struct RequestData: Codable {
@ -89,7 +97,8 @@ class OpenGroupAPITests: XCTestCase {
sign: testSign,
genericHash: testGenericHash,
ed25519: TestEd25519.self,
nonceGenerator: TestNonceGenerator(),
nonceGenerator16: TestNonce16Generator(),
nonceGenerator24: TestNonce24Generator(),
date: Date(timeIntervalSince1970: 1234567890)
)
@ -142,21 +151,35 @@ class OpenGroupAPITests: XCTestCase {
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: OpenGroupAPI.Capabilities(capabilities: [], missing: nil)
body: OpenGroupAPI.Capabilities(capabilities: [], missing: nil),
failedToParseBody: false
)
),
try! JSONEncoder().encode(
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: try! JSONDecoder().decode(OpenGroupAPI.RoomPollInfo.self, from: "{}".data(using: .utf8)!)
body: try! JSONDecoder().decode(
OpenGroupAPI.RoomPollInfo.self,
from: """
{
\"token\":\"test\",
\"active_users\":1,
\"read\":true,
\"write\":true,
\"upload\":true
}
""".data(using: .utf8)!
),
failedToParseBody: false
)
),
try! JSONEncoder().encode(
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: [OpenGroupAPI.Message]()
body: [OpenGroupAPI.Message](),
failedToParseBody: false
)
)
]
@ -166,7 +189,7 @@ class OpenGroupAPITests: XCTestCase {
}
dependencies = dependencies.with(api: LocalTestApi.self)
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable)]? = nil
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable?)]? = nil
var error: Error? = nil
OpenGroupAPI.poll("testServer", using: dependencies)
@ -197,7 +220,7 @@ class OpenGroupAPITests: XCTestCase {
}
func testPollReturnsAnErrorWhenGivenNoData() throws {
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable)]? = nil
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable?)]? = nil
var error: Error? = nil
OpenGroupAPI.poll("testServer", using: dependencies)
@ -220,7 +243,7 @@ class OpenGroupAPITests: XCTestCase {
}
dependencies = dependencies.with(api: LocalTestApi.self)
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable)]? = nil
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable?)]? = nil
var error: Error? = nil
OpenGroupAPI.poll("testServer", using: dependencies)
@ -243,7 +266,7 @@ class OpenGroupAPITests: XCTestCase {
}
dependencies = dependencies.with(api: LocalTestApi.self)
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable)]? = nil
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable?)]? = nil
var error: Error? = nil
OpenGroupAPI.poll("testServer", using: dependencies)
@ -266,7 +289,7 @@ class OpenGroupAPITests: XCTestCase {
}
dependencies = dependencies.with(api: LocalTestApi.self)
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable)]? = nil
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable?)]? = nil
var error: Error? = nil
OpenGroupAPI.poll("testServer", using: dependencies)
@ -291,14 +314,27 @@ class OpenGroupAPITests: XCTestCase {
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: OpenGroupAPI.Capabilities(capabilities: [], missing: nil)
body: OpenGroupAPI.Capabilities(capabilities: [], missing: nil),
failedToParseBody: false
)
),
try! JSONEncoder().encode(
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: try! JSONDecoder().decode(OpenGroupAPI.RoomPollInfo.self, from: "{}".data(using: .utf8)!)
body: try! JSONDecoder().decode(
OpenGroupAPI.RoomPollInfo.self,
from: """
{
\"token\":\"test\",
\"active_users\":1,
\"read\":true,
\"write\":true,
\"upload\":true
}
""".data(using: .utf8)!
),
failedToParseBody: false
)
)
]
@ -308,7 +344,7 @@ class OpenGroupAPITests: XCTestCase {
}
dependencies = dependencies.with(api: LocalTestApi.self)
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable)]? = nil
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable?)]? = nil
var error: Error? = nil
OpenGroupAPI.poll("testServer", using: dependencies)
@ -333,21 +369,24 @@ class OpenGroupAPITests: XCTestCase {
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: OpenGroupAPI.PinnedMessage(id: 1, pinnedAt: 1, pinnedBy: "")
body: OpenGroupAPI.PinnedMessage(id: 1, pinnedAt: 1, pinnedBy: ""),
failedToParseBody: false
)
),
try! JSONEncoder().encode(
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: OpenGroupAPI.PinnedMessage(id: 1, pinnedAt: 1, pinnedBy: "")
body: OpenGroupAPI.PinnedMessage(id: 1, pinnedAt: 1, pinnedBy: ""),
failedToParseBody: false
)
),
try! JSONEncoder().encode(
OpenGroupAPI.BatchSubResponse(
code: 200,
headers: [:],
body: OpenGroupAPI.PinnedMessage(id: 1, pinnedAt: 1, pinnedBy: "")
body: OpenGroupAPI.PinnedMessage(id: 1, pinnedAt: 1, pinnedBy: ""),
failedToParseBody: false
)
)
]
@ -357,7 +396,7 @@ class OpenGroupAPITests: XCTestCase {
}
dependencies = dependencies.with(api: LocalTestApi.self)
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable)]? = nil
var response: [OpenGroupAPI.Endpoint: (OnionRequestResponseInfoType, Codable?)]? = nil
var error: Error? = nil
OpenGroupAPI.poll("testServer", using: dependencies)
@ -566,6 +605,7 @@ class OpenGroupAPITests: XCTestCase {
func getAeadXChaCha20Poly1305Ietf() -> AeadXChaCha20Poly1305IetfType { return Sodium().aead.xchacha20poly1305ietf }
func getSign() -> SignType { return Sodium().sign }
func generateBlindingFactor(serverPublicKey: String) -> Bytes? { return nil }
func blindedKeyPair(serverPublicKey: String, edKeyPair: Box.KeyPair, genericHash: GenericHashType) -> Box.KeyPair? {
return nil
}
@ -573,7 +613,14 @@ class OpenGroupAPITests: XCTestCase {
return nil
}
func sharedEdSecret(_ firstKeyBytes: [UInt8], _ secondKeyBytes: [UInt8]) -> Bytes? { return nil }
func combineKeys(lhsKeyBytes: Bytes, rhsKeyBytes: Bytes) -> Bytes? { return nil }
func sharedBlindedEncryptionKey(secretKey a: Bytes, otherBlindedPublicKey: Bytes, fromBlindedPublicKey kA: Bytes, toBlindedPublicKey kB: Bytes, genericHash: GenericHashType) -> Bytes? {
return nil
}
func sessionId(_ sessionId: String, matchesBlindedId blindedSessionId: String, serverPublicKey: String) -> Bool {
return false
}
}
testStorage.mockData[.openGroupServer] = OpenGroupAPI.Server(
name: "testServer",
@ -604,6 +651,7 @@ class OpenGroupAPITests: XCTestCase {
func getAeadXChaCha20Poly1305Ietf() -> AeadXChaCha20Poly1305IetfType { return Sodium().aead.xchacha20poly1305ietf }
func getSign() -> SignType { return Sodium().sign }
func generateBlindingFactor(serverPublicKey: String) -> Bytes? { return nil }
func blindedKeyPair(serverPublicKey: String, edKeyPair: Box.KeyPair, genericHash: GenericHashType) -> Box.KeyPair? {
return Box.KeyPair(
publicKey: Data.data(fromHex: "7aecdcade88d881d2327ab011afd2e04c2ec6acffc9e9df45aaf78a151bd2f7d")!.bytes,
@ -614,7 +662,14 @@ class OpenGroupAPITests: XCTestCase {
return nil
}
func sharedEdSecret(_ firstKeyBytes: [UInt8], _ secondKeyBytes: [UInt8]) -> Bytes? { return nil }
func combineKeys(lhsKeyBytes: Bytes, rhsKeyBytes: Bytes) -> Bytes? { return nil }
func sharedBlindedEncryptionKey(secretKey a: Bytes, otherBlindedPublicKey: Bytes, fromBlindedPublicKey kA: Bytes, toBlindedPublicKey kB: Bytes, genericHash: GenericHashType) -> Bytes? {
return nil
}
func sessionId(_ sessionId: String, matchesBlindedId blindedSessionId: String, serverPublicKey: String) -> Bool {
return false
}
}
testStorage.mockData[.openGroupServer] = OpenGroupAPI.Server(
name: "testServer",
@ -641,8 +696,11 @@ class OpenGroupAPITests: XCTestCase {
func testItFailsToSignIfUnblindedAndTheSignatureDoesNotGetGenerated() throws {
class InvalidSign: SignType {
var PublicKeyBytes: Int = 32
func signature(message: Bytes, secretKey: Bytes) -> Bytes? { return nil }
func verify(message: Bytes, publicKey: Bytes, signature: Bytes) -> Bool { return false }
func toX25519(ed25519PublicKey: Bytes) -> Bytes? { return nil }
}
testStorage.mockData[.openGroupServer] = OpenGroupAPI.Server(
name: "testServer",

@ -7,10 +7,14 @@ import Sodium
@testable import SessionMessagingKit
class TestAeadXChaCha20Poly1305Ietf: AeadXChaCha20Poly1305IetfType, Mockable {
var KeyBytes: Int = 32
var ABytes: Int = 16
// MARK: - Mockable
enum DataKey: Hashable {
case encrypt
case decrypt
}
typealias Key = DataKey
@ -19,7 +23,11 @@ class TestAeadXChaCha20Poly1305Ietf: AeadXChaCha20Poly1305IetfType, Mockable {
// MARK: - SignType
func encrypt(message: Bytes, secretKey: Aead.XChaCha20Poly1305Ietf.Key, additionalData: Bytes?) -> (authenticatedCipherText: Bytes, nonce: Aead.XChaCha20Poly1305Ietf.Nonce)? {
return (mockData[.encrypt] as? (authenticatedCipherText: Bytes, nonce: Aead.XChaCha20Poly1305Ietf.Nonce))
func encrypt(message: Bytes, secretKey: Bytes, nonce: Bytes, additionalData: Bytes?) -> Bytes? {
return (mockData[.encrypt] as? Bytes)
}
func decrypt(authenticatedCipherText: Bytes, secretKey: Bytes, nonce: Bytes, additionalData: Bytes?) -> Bytes? {
return (mockData[.decrypt] as? Bytes)
}
}

@ -7,11 +7,14 @@ import Sodium
@testable import SessionMessagingKit
class TestSign: SignType, Mockable {
var PublicKeyBytes: Int = 32
// MARK: - Mockable
enum DataKey: Hashable {
case signature
case verify
case toX25519
}
typealias Key = DataKey
@ -27,4 +30,8 @@ class TestSign: SignType, Mockable {
func verify(message: Bytes, publicKey: Bytes, signature: Bytes) -> Bool {
return (mockData[.verify] as! Bool)
}
func toX25519(ed25519PublicKey: Bytes) -> Bytes? {
return (mockData[.toX25519] as? Bytes)
}
}

@ -13,9 +13,12 @@ class TestSodium: SodiumType, Mockable {
case genericHash
case aeadXChaCha20Poly1305Ietf
case sign
case blindingFactor
case blindedKeyPair
case sogsSignature
case sharedEdSecret
case combinedKeys
case sharedBlindedEncryptionKey
case sessionIdMatches
}
typealias Key = DataKey
@ -32,6 +35,8 @@ class TestSodium: SodiumType, Mockable {
func getSign() -> SignType { return (mockData[.sign] as! SignType) }
func generateBlindingFactor(serverPublicKey: String) -> Bytes? { return (mockData[.blindingFactor] as? Bytes) }
func blindedKeyPair(serverPublicKey: String, edKeyPair: Box.KeyPair, genericHash: GenericHashType) -> Box.KeyPair? {
return (mockData[.blindedKeyPair] as? Box.KeyPair)
}
@ -40,7 +45,15 @@ class TestSodium: SodiumType, Mockable {
return (mockData[.sogsSignature] as? Bytes)
}
func sharedEdSecret(_ firstKeyBytes: [UInt8], _ secondKeyBytes: [UInt8]) -> Bytes? {
return (mockData[.sharedEdSecret] as? Bytes)
func combineKeys(lhsKeyBytes: Bytes, rhsKeyBytes: Bytes) -> Bytes? {
return (mockData[.combinedKeys] as? Bytes)
}
func sharedBlindedEncryptionKey(secretKey a: Bytes, otherBlindedPublicKey: Bytes, fromBlindedPublicKey kA: Bytes, toBlindedPublicKey kB: Bytes, genericHash: GenericHashType) -> Bytes? {
return (mockData[.sharedBlindedEncryptionKey] as? Bytes)
}
func sessionId(_ sessionId: String, matchesBlindedId blindedSessionId: String, serverPublicKey: String) -> Bool {
return ((mockData[.sessionIdMatches] as? Bool) ?? false)
}
}

@ -18,6 +18,8 @@ class TestStorage: SessionMessagingKitStorageProtocol, Mockable {
case openGroupServer
case openGroupImage
case openGroupUserCount
case openGroupSequenceNumber
case openGroupLatestMessageId
}
typealias Key = DataKey
@ -47,6 +49,7 @@ class TestStorage: SessionMessagingKitStorageProtocol, Mockable {
func getUserED25519KeyPair() -> Box.KeyPair? { return (mockData[.userEdKeyPair] as? Box.KeyPair) }
func getUser() -> Contact? { return nil }
func getAllContacts() -> Set<Contact> { return Set() }
func getAllContacts(with transaction: YapDatabaseReadTransaction) -> Set<Contact> { return Set() }
// MARK: - Closed Groups
@ -66,12 +69,6 @@ class TestStorage: SessionMessagingKitStorageProtocol, Mockable {
func resumeMessageSendJobIfNeeded(_ messageSendJobID: String) {}
func isJobCanceled(_ job: Job) -> Bool { return true }
// MARK: - Authorization
func getAuthToken(for room: String, on server: String) -> String? { return nil }
func setAuthToken(for room: String, on server: String, to newValue: String, using transaction: Any) {}
func removeAuthToken(for room: String, on server: String, using transaction: Any) {}
// MARK: - Open Groups
func getAllOpenGroups() -> [String: OpenGroup] { return (mockData[.allOpenGroups] as! [String: OpenGroup]) }
@ -96,6 +93,40 @@ class TestStorage: SessionMessagingKitStorageProtocol, Mockable {
mockData[.openGroupUserCount] = newValue
}
func getOpenGroupSequenceNumber(for room: String, on server: String) -> Int64? {
let data: [String: Int64] = ((mockData[.openGroupSequenceNumber] as? [String: Int64]) ?? [:])
return data["\(server).\(room)"]
}
func setOpenGroupSequenceNumber(for room: String, on server: String, to newValue: Int64, using transaction: Any) {
var updatedData: [String: Int64] = ((mockData[.openGroupSequenceNumber] as? [String: Int64]) ?? [:])
updatedData["\(server).\(room)"] = newValue
mockData[.openGroupSequenceNumber] = updatedData
}
func removeOpenGroupSequenceNumber(for room: String, on server: String, using transaction: Any) {
var updatedData: [String: Int64] = ((mockData[.openGroupSequenceNumber] as? [String: Int64]) ?? [:])
updatedData["\(server).\(room)"] = nil
mockData[.openGroupSequenceNumber] = updatedData
}
func getOpenGroupInboxLatestMessageId(for server: String) -> Int64? {
let data: [String: Int64] = ((mockData[.openGroupLatestMessageId] as? [String: Int64]) ?? [:])
return data[server]
}
func setOpenGroupInboxLatestMessageId(for server: String, to newValue: Int64, using transaction: Any) {
var updatedData: [String: Int64] = ((mockData[.openGroupLatestMessageId] as? [String: Int64]) ?? [:])
updatedData[server] = newValue
mockData[.openGroupLatestMessageId] = updatedData
}
func removeOpenGroupInboxLatestMessageId(for server: String, using transaction: Any) {
var updatedData: [String: Int64] = ((mockData[.openGroupLatestMessageId] as? [String: Int64]) ?? [:])
updatedData[server] = nil
mockData[.openGroupLatestMessageId] = updatedData
}
// MARK: - Open Group Public Keys
func getOpenGroupPublicKey(for server: String) -> String? {
@ -108,19 +139,10 @@ class TestStorage: SessionMessagingKitStorageProtocol, Mockable {
func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any) {}
// MARK: - Last Message Server ID
func getLastMessageServerID(for room: String, on server: String) -> Int64? { return nil }
func setLastMessageServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {}
func removeLastMessageServerID(for room: String, on server: String, using transaction: Any) {}
// MARK: - Last Deletion Server ID
func getLastDeletionServerID(for room: String, on server: String) -> Int64? { return nil }
func setLastDeletionServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {}
func removeLastDeletionServerID(for room: String, on server: String, using transaction: Any) {}
// MARK: - Message Handling
func getAllMessageRequestThreads() -> [String: TSContactThread] { return [:] }
func getAllMessageRequestThreads(using transaction: YapDatabaseReadTransaction) -> [String: TSContactThread] { return [:] }
func getReceivedMessageTimestamps(using transaction: Any) -> [UInt64] { return [] }
func addReceivedMessageTimestamp(_ timestamp: UInt64, using transaction: Any) {}

Loading…
Cancel
Save