mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
588 lines
33 KiB
Swift
588 lines
33 KiB
Swift
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
import Foundation
|
|
import Sodium
|
|
import SessionUtil
|
|
import SessionUtilitiesKit
|
|
import SessionMessagingKit
|
|
|
|
import Quick
|
|
import Nimble
|
|
|
|
/// This spec is designed to replicate the initial test cases for the libSession-util to ensure the behaviour matches
|
|
class ConfigUserGroupsSpec {
|
|
// MARK: - Spec
|
|
|
|
static func spec() {
|
|
it("parses community URLs correctly") {
|
|
let result1 = SessionUtil.parseCommunity(url: [
|
|
"https://example.com/",
|
|
"SomeRoom?public_key=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
|
].joined())
|
|
let result2 = SessionUtil.parseCommunity(url: [
|
|
"HTTPS://EXAMPLE.COM/",
|
|
"sOMErOOM?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
|
].joined())
|
|
let result3 = SessionUtil.parseCommunity(url: [
|
|
"HTTPS://EXAMPLE.COM/r/",
|
|
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
|
].joined())
|
|
let result4 = SessionUtil.parseCommunity(url: [
|
|
"http://example.com/r/",
|
|
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
|
].joined())
|
|
let result5 = SessionUtil.parseCommunity(url: [
|
|
"HTTPS://EXAMPLE.com:443/r/",
|
|
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
|
].joined())
|
|
let result6 = SessionUtil.parseCommunity(url: [
|
|
"HTTP://EXAMPLE.com:80/r/",
|
|
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
|
].joined())
|
|
let result7 = SessionUtil.parseCommunity(url: [
|
|
"http://example.com:80/r/",
|
|
"someroom?public_key=ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8"
|
|
].joined())
|
|
let result8 = SessionUtil.parseCommunity(url: [
|
|
"http://example.com:80/r/",
|
|
"someroom?public_key=yrtwk3hjixg66yjdeiuauk6p7hy1gtm8tgih55abrpnsxnpm3zzo"
|
|
].joined())
|
|
|
|
expect(result1?.server).to(equal("https://example.com"))
|
|
expect(result1?.server).to(equal(result2?.server))
|
|
expect(result1?.server).to(equal(result3?.server))
|
|
expect(result1?.server).toNot(equal(result4?.server))
|
|
expect(result4?.server).to(equal("http://example.com"))
|
|
expect(result1?.server).to(equal(result5?.server))
|
|
expect(result4?.server).to(equal(result6?.server))
|
|
expect(result4?.server).to(equal(result7?.server))
|
|
expect(result4?.server).to(equal(result8?.server))
|
|
expect(result1?.room).to(equal("SomeRoom"))
|
|
expect(result2?.room).to(equal("sOMErOOM"))
|
|
expect(result3?.room).to(equal("someroom"))
|
|
expect(result4?.room).to(equal("someroom"))
|
|
expect(result5?.room).to(equal("someroom"))
|
|
expect(result6?.room).to(equal("someroom"))
|
|
expect(result7?.room).to(equal("someroom"))
|
|
expect(result8?.room).to(equal("someroom"))
|
|
expect(result1?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(result2?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(result3?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(result4?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(result5?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(result6?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(result7?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(result8?.publicKey)
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
}
|
|
|
|
it("generates UserGroup configs correctly") {
|
|
let createdTs: Int64 = 1680064059
|
|
let nowTs: Int64 = Int64(Date().timeIntervalSince1970)
|
|
let seed: Data = Data(hex: "0123456789abcdef0123456789abcdef")
|
|
|
|
// FIXME: Would be good to move these into the libSession-util instead of using Sodium separately
|
|
let identity = try! Identity.generate(from: seed)
|
|
var edSK: [UInt8] = identity.ed25519KeyPair.secretKey
|
|
expect(edSK.toHexString().suffix(64))
|
|
.to(equal("4cb76fdc6d32278e3f83dbf608360ecc6b65727934b85d2fb86862ff98c46ab7"))
|
|
expect(identity.x25519KeyPair.publicKey.toHexString())
|
|
.to(equal("d2ad010eeb72d72e561d9de7bd7b6989af77dcabffa03a5111a6c859ae5c3a72"))
|
|
expect(String(edSK.toHexString().prefix(32))).to(equal(seed.toHexString()))
|
|
|
|
// Initialize a brand new, empty config because we have no dump data to deal with.
|
|
let error: UnsafeMutablePointer<CChar>? = nil
|
|
var conf: UnsafeMutablePointer<config_object>? = nil
|
|
expect(user_groups_init(&conf, &edSK, nil, 0, error)).to(equal(0))
|
|
error?.deallocate()
|
|
|
|
// Empty contacts shouldn't have an existing contact
|
|
let definitelyRealId: String = "055000000000000000000000000000000000000000000000000000000000000000"
|
|
var cDefinitelyRealId: [CChar] = definitelyRealId.cArray.nullTerminated()
|
|
let legacyGroup1: UnsafeMutablePointer<ugroups_legacy_group_info>? = user_groups_get_legacy_group(conf, &cDefinitelyRealId)
|
|
expect(legacyGroup1?.pointee).to(beNil())
|
|
expect(user_groups_size(conf)).to(equal(0))
|
|
|
|
let legacyGroup2: UnsafeMutablePointer<ugroups_legacy_group_info> = user_groups_get_or_construct_legacy_group(conf, &cDefinitelyRealId)
|
|
expect(legacyGroup2.pointee).toNot(beNil())
|
|
expect(String(libSessionVal: legacyGroup2.pointee.session_id))
|
|
.to(equal(definitelyRealId))
|
|
expect(legacyGroup2.pointee.disappearing_timer).to(equal(0))
|
|
expect(String(libSessionVal: legacyGroup2.pointee.enc_pubkey, fixedLength: 32)).to(equal(""))
|
|
expect(String(libSessionVal: legacyGroup2.pointee.enc_seckey, fixedLength: 32)).to(equal(""))
|
|
expect(legacyGroup2.pointee.priority).to(equal(0))
|
|
expect(String(libSessionVal: legacyGroup2.pointee.name)).to(equal(""))
|
|
expect(legacyGroup2.pointee.joined_at).to(equal(0))
|
|
expect(legacyGroup2.pointee.notifications).to(equal(CONVO_NOTIFY_DEFAULT))
|
|
expect(legacyGroup2.pointee.mute_until).to(equal(0))
|
|
|
|
// Iterate through and make sure we got everything we expected
|
|
var membersSeen1: [String: Bool] = [:]
|
|
var memberSessionId1: UnsafePointer<CChar>? = nil
|
|
var memberAdmin1: Bool = false
|
|
let membersIt1: OpaquePointer = ugroups_legacy_members_begin(legacyGroup2)
|
|
|
|
while ugroups_legacy_members_next(membersIt1, &memberSessionId1, &memberAdmin1) {
|
|
membersSeen1[String(cString: memberSessionId1!)] = memberAdmin1
|
|
}
|
|
|
|
ugroups_legacy_members_free(membersIt1)
|
|
|
|
expect(membersSeen1).to(beEmpty())
|
|
|
|
// No need to sync a conversation with a default state
|
|
expect(config_needs_push(conf)).to(beFalse())
|
|
expect(config_needs_dump(conf)).to(beFalse())
|
|
|
|
// We don't need to push since we haven't changed anything, so this call is mainly just for
|
|
// testing:
|
|
let pushData1: UnsafeMutablePointer<config_push_data> = config_push(conf)
|
|
expect(pushData1.pointee.seqno).to(equal(0))
|
|
expect([String](pointer: pushData1.pointee.obsolete, count: pushData1.pointee.obsolete_len))
|
|
.to(beEmpty())
|
|
expect(pushData1.pointee.config_len).to(equal(256))
|
|
pushData1.deallocate()
|
|
|
|
let users: [String] = [
|
|
"050000000000000000000000000000000000000000000000000000000000000000",
|
|
"051111111111111111111111111111111111111111111111111111111111111111",
|
|
"052222222222222222222222222222222222222222222222222222222222222222",
|
|
"053333333333333333333333333333333333333333333333333333333333333333",
|
|
"054444444444444444444444444444444444444444444444444444444444444444",
|
|
"055555555555555555555555555555555555555555555555555555555555555555",
|
|
"056666666666666666666666666666666666666666666666666666666666666666"
|
|
]
|
|
var cUsers: [[CChar]] = users.map { $0.cArray.nullTerminated() }
|
|
legacyGroup2.pointee.name = "Englishmen".toLibSession()
|
|
legacyGroup2.pointee.disappearing_timer = 60
|
|
legacyGroup2.pointee.joined_at = createdTs
|
|
legacyGroup2.pointee.notifications = CONVO_NOTIFY_ALL
|
|
legacyGroup2.pointee.mute_until = (nowTs + 3600)
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[0], false)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[1], true)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[2], false)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[4], true)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[5], false)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[2], false)).to(beFalse())
|
|
|
|
// Flip to and from admin
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[2], true)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup2, &cUsers[1], false)).to(beTrue())
|
|
|
|
expect(ugroups_legacy_member_remove(legacyGroup2, &cUsers[5])).to(beTrue())
|
|
expect(ugroups_legacy_member_remove(legacyGroup2, &cUsers[4])).to(beTrue())
|
|
|
|
var membersSeen2: [String: Bool] = [:]
|
|
var memberSessionId2: UnsafePointer<CChar>? = nil
|
|
var memberAdmin2: Bool = false
|
|
let membersIt2: OpaquePointer = ugroups_legacy_members_begin(legacyGroup2)
|
|
|
|
while ugroups_legacy_members_next(membersIt2, &memberSessionId2, &memberAdmin2) {
|
|
membersSeen2[String(cString: memberSessionId2!)] = memberAdmin2
|
|
}
|
|
|
|
ugroups_legacy_members_free(membersIt2)
|
|
|
|
expect(membersSeen2).to(equal([
|
|
"050000000000000000000000000000000000000000000000000000000000000000": false,
|
|
"051111111111111111111111111111111111111111111111111111111111111111": false,
|
|
"052222222222222222222222222222222222222222222222222222222222222222": true
|
|
]))
|
|
|
|
// FIXME: Would be good to move these into the libSession-util instead of using Sodium separately
|
|
let groupSeed: Data = Data(hex: "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")
|
|
let groupEd25519KeyPair = Sodium().sign.keyPair(seed: groupSeed.bytes)!
|
|
let groupX25519PublicKey = Sodium().sign.toX25519(ed25519PublicKey: groupEd25519KeyPair.publicKey)!
|
|
|
|
// Note: this isn't exactly what Session actually does here for legacy closed
|
|
// groups (rather it uses X25519 keys) but for this test the distinction doesn't matter.
|
|
legacyGroup2.pointee.enc_pubkey = Data(groupX25519PublicKey).toLibSession()
|
|
legacyGroup2.pointee.enc_seckey = Data(groupEd25519KeyPair.secretKey).toLibSession()
|
|
legacyGroup2.pointee.priority = 3
|
|
|
|
expect(Data(libSessionVal: legacyGroup2.pointee.enc_pubkey, count: 32).toHexString())
|
|
.to(equal("c5ba413c336f2fe1fb9a2c525f8a86a412a1db128a7841b4e0e217fa9eb7fd5e"))
|
|
expect(Data(libSessionVal: legacyGroup2.pointee.enc_seckey, count: 32).toHexString())
|
|
.to(equal("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"))
|
|
|
|
// The new data doesn't get stored until we call this:
|
|
user_groups_set_free_legacy_group(conf, legacyGroup2)
|
|
|
|
let legacyGroup3: UnsafeMutablePointer<ugroups_legacy_group_info>? = user_groups_get_legacy_group(conf, &cDefinitelyRealId)
|
|
expect(legacyGroup3?.pointee).toNot(beNil())
|
|
expect(config_needs_push(conf)).to(beTrue())
|
|
expect(config_needs_dump(conf)).to(beTrue())
|
|
ugroups_legacy_group_free(legacyGroup3)
|
|
|
|
let communityPubkey: String = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
|
var cCommunityPubkey: [UInt8] = Data(hex: communityPubkey).cArray
|
|
var cCommunityBaseUrl: [CChar] = "http://Example.ORG:5678".cArray.nullTerminated()
|
|
var cCommunityRoom: [CChar] = "SudokuRoom".cArray.nullTerminated()
|
|
var community1: ugroups_community_info = ugroups_community_info()
|
|
expect(user_groups_get_or_construct_community(conf, &community1, &cCommunityBaseUrl, &cCommunityRoom, &cCommunityPubkey))
|
|
.to(beTrue())
|
|
|
|
expect(String(libSessionVal: community1.base_url)).to(equal("http://example.org:5678")) // Note: lower-case
|
|
expect(String(libSessionVal: community1.room)).to(equal("SudokuRoom")) // Note: case-preserving
|
|
expect(Data(libSessionVal: community1.pubkey, count: 32).toHexString())
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
community1.priority = 14
|
|
|
|
// The new data doesn't get stored until we call this:
|
|
user_groups_set_community(conf, &community1)
|
|
|
|
// incremented since we made changes (this only increments once between
|
|
// dumps; even though we changed two fields here).
|
|
let pushData2: UnsafeMutablePointer<config_push_data> = config_push(conf)
|
|
expect(pushData2.pointee.seqno).to(equal(1))
|
|
expect([String](pointer: pushData2.pointee.obsolete, count: pushData2.pointee.obsolete_len))
|
|
.to(beEmpty())
|
|
|
|
// Pretend we uploaded it
|
|
let fakeHash1: String = "fakehash1"
|
|
var cFakeHash1: [CChar] = fakeHash1.cArray.nullTerminated()
|
|
config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash1)
|
|
expect(config_needs_dump(conf)).to(beTrue())
|
|
expect(config_needs_push(conf)).to(beFalse())
|
|
|
|
var dump1: UnsafeMutablePointer<UInt8>? = nil
|
|
var dump1Len: Int = 0
|
|
config_dump(conf, &dump1, &dump1Len)
|
|
|
|
let error2: UnsafeMutablePointer<CChar>? = nil
|
|
var conf2: UnsafeMutablePointer<config_object>? = nil
|
|
expect(user_groups_init(&conf2, &edSK, dump1, dump1Len, error2)).to(equal(0))
|
|
error2?.deallocate()
|
|
dump1?.deallocate()
|
|
|
|
expect(config_needs_dump(conf)).to(beFalse()) // Because we just called dump() above, to load up conf2
|
|
expect(config_needs_push(conf)).to(beFalse())
|
|
|
|
let pushData3: UnsafeMutablePointer<config_push_data> = config_push(conf)
|
|
expect(pushData3.pointee.seqno).to(equal(1))
|
|
expect([String](pointer: pushData3.pointee.obsolete, count: pushData3.pointee.obsolete_len))
|
|
.to(beEmpty())
|
|
pushData3.deallocate()
|
|
|
|
let currentHashes1: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf)
|
|
expect([String](pointer: currentHashes1?.pointee.value, count: currentHashes1?.pointee.len))
|
|
.to(equal(["fakehash1"]))
|
|
currentHashes1?.deallocate()
|
|
|
|
expect(config_needs_push(conf2)).to(beFalse())
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
|
|
let pushData4: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
expect(pushData4.pointee.seqno).to(equal(1))
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
expect([String](pointer: pushData4.pointee.obsolete, count: pushData4.pointee.obsolete_len))
|
|
.to(beEmpty())
|
|
pushData4.deallocate()
|
|
|
|
let currentHashes2: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
|
|
expect([String](pointer: currentHashes2?.pointee.value, count: currentHashes2?.pointee.len))
|
|
.to(equal(["fakehash1"]))
|
|
currentHashes2?.deallocate()
|
|
|
|
expect(user_groups_size(conf2)).to(equal(2))
|
|
expect(user_groups_size_communities(conf2)).to(equal(1))
|
|
expect(user_groups_size_legacy_groups(conf2)).to(equal(1))
|
|
|
|
let legacyGroup4: UnsafeMutablePointer<ugroups_legacy_group_info>? = user_groups_get_legacy_group(conf2, &cDefinitelyRealId)
|
|
expect(legacyGroup4?.pointee).toNot(beNil())
|
|
expect(String(libSessionVal: legacyGroup4?.pointee.enc_pubkey, fixedLength: 32)).to(equal(""))
|
|
expect(String(libSessionVal: legacyGroup4?.pointee.enc_seckey, fixedLength: 32)).to(equal(""))
|
|
expect(legacyGroup4?.pointee.disappearing_timer).to(equal(60))
|
|
expect(String(libSessionVal: legacyGroup4?.pointee.session_id)).to(equal(definitelyRealId))
|
|
expect(legacyGroup4?.pointee.priority).to(equal(3))
|
|
expect(String(libSessionVal: legacyGroup4?.pointee.name)).to(equal("Englishmen"))
|
|
expect(legacyGroup4?.pointee.joined_at).to(equal(createdTs))
|
|
expect(legacyGroup2.pointee.notifications).to(equal(CONVO_NOTIFY_ALL))
|
|
expect(legacyGroup2.pointee.mute_until).to(equal(nowTs + 3600))
|
|
|
|
var membersSeen3: [String: Bool] = [:]
|
|
var memberSessionId3: UnsafePointer<CChar>? = nil
|
|
var memberAdmin3: Bool = false
|
|
let membersIt3: OpaquePointer = ugroups_legacy_members_begin(legacyGroup4)
|
|
|
|
while ugroups_legacy_members_next(membersIt3, &memberSessionId3, &memberAdmin3) {
|
|
membersSeen3[String(cString: memberSessionId3!)] = memberAdmin3
|
|
}
|
|
|
|
ugroups_legacy_members_free(membersIt3)
|
|
ugroups_legacy_group_free(legacyGroup4)
|
|
|
|
expect(membersSeen3).to(equal([
|
|
"050000000000000000000000000000000000000000000000000000000000000000": false,
|
|
"051111111111111111111111111111111111111111111111111111111111111111": false,
|
|
"052222222222222222222222222222222222222222222222222222222222222222": true
|
|
]))
|
|
|
|
expect(config_needs_push(conf2)).to(beFalse())
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
|
|
let pushData5: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
expect(pushData5.pointee.seqno).to(equal(1))
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
pushData5.deallocate()
|
|
|
|
for targetConf in [conf, conf2] {
|
|
// Iterate through and make sure we got everything we expected
|
|
var seen: [String] = []
|
|
|
|
var c1: ugroups_legacy_group_info = ugroups_legacy_group_info()
|
|
var c2: ugroups_community_info = ugroups_community_info()
|
|
let it: OpaquePointer = user_groups_iterator_new(targetConf)
|
|
|
|
while !user_groups_iterator_done(it) {
|
|
if user_groups_it_is_legacy_group(it, &c1) {
|
|
var memberCount: Int = 0
|
|
var adminCount: Int = 0
|
|
ugroups_legacy_members_count(&c1, &memberCount, &adminCount)
|
|
seen.append("legacy: \(String(libSessionVal: c1.name)), \(adminCount) admins, \(memberCount) members")
|
|
}
|
|
else if user_groups_it_is_community(it, &c2) {
|
|
seen.append("community: \(String(libSessionVal: c2.base_url))/r/\(String(libSessionVal: c2.room))")
|
|
}
|
|
else {
|
|
seen.append("unknown")
|
|
}
|
|
|
|
user_groups_iterator_advance(it)
|
|
}
|
|
|
|
user_groups_iterator_free(it)
|
|
|
|
expect(seen).to(equal([
|
|
"community: http://example.org:5678/r/SudokuRoom",
|
|
"legacy: Englishmen, 1 admins, 2 members"
|
|
]))
|
|
}
|
|
|
|
var cCommunity2BaseUrl: [CChar] = "http://example.org:5678".cArray.nullTerminated()
|
|
var cCommunity2Room: [CChar] = "sudokuRoom".cArray.nullTerminated()
|
|
var community2: ugroups_community_info = ugroups_community_info()
|
|
expect(user_groups_get_community(conf2, &community2, &cCommunity2BaseUrl, &cCommunity2Room))
|
|
.to(beTrue())
|
|
expect(String(libSessionVal: community2.base_url)).to(equal("http://example.org:5678"))
|
|
expect(String(libSessionVal: community2.room)).to(equal("SudokuRoom")) // Case preserved from the stored value, not the input value
|
|
expect(Data(libSessionVal: community2.pubkey, count: 32).toHexString())
|
|
.to(equal("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"))
|
|
expect(community2.priority).to(equal(14))
|
|
|
|
expect(config_needs_push(conf2)).to(beFalse())
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
|
|
let pushData6: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
expect(pushData6.pointee.seqno).to(equal(1))
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
pushData6.deallocate()
|
|
|
|
community2.room = "sudokuRoom".toLibSession() // Change capitalization
|
|
user_groups_set_community(conf2, &community2)
|
|
|
|
expect(config_needs_push(conf2)).to(beTrue())
|
|
expect(config_needs_dump(conf2)).to(beTrue())
|
|
|
|
let fakeHash2: String = "fakehash2"
|
|
var cFakeHash2: [CChar] = fakeHash2.cArray.nullTerminated()
|
|
let pushData7: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
expect(pushData7.pointee.seqno).to(equal(2))
|
|
config_confirm_pushed(conf2, pushData7.pointee.seqno, &cFakeHash2)
|
|
expect([String](pointer: pushData7.pointee.obsolete, count: pushData7.pointee.obsolete_len))
|
|
.to(equal([fakeHash1]))
|
|
|
|
let currentHashes3: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
|
|
expect([String](pointer: currentHashes3?.pointee.value, count: currentHashes3?.pointee.len))
|
|
.to(equal([fakeHash2]))
|
|
currentHashes3?.deallocate()
|
|
|
|
var dump2: UnsafeMutablePointer<UInt8>? = nil
|
|
var dump2Len: Int = 0
|
|
config_dump(conf2, &dump2, &dump2Len)
|
|
|
|
expect(config_needs_push(conf2)).to(beFalse())
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
|
|
let pushData8: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
expect(pushData8.pointee.seqno).to(equal(2))
|
|
config_confirm_pushed(conf2, pushData8.pointee.seqno, &cFakeHash2)
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
|
|
var mergeHashes1: [UnsafePointer<CChar>?] = [cFakeHash2].unsafeCopy()
|
|
var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData8.pointee.config)]
|
|
var mergeSize1: [Int] = [pushData8.pointee.config_len]
|
|
expect(config_merge(conf, &mergeHashes1, &mergeData1, &mergeSize1, 1)).to(equal(1))
|
|
pushData8.deallocate()
|
|
|
|
var cCommunity3BaseUrl: [CChar] = "http://example.org:5678".cArray.nullTerminated()
|
|
var cCommunity3Room: [CChar] = "SudokuRoom".cArray.nullTerminated()
|
|
var community3: ugroups_community_info = ugroups_community_info()
|
|
expect(user_groups_get_community(conf, &community3, &cCommunity3BaseUrl, &cCommunity3Room))
|
|
.to(beTrue())
|
|
expect(String(libSessionVal: community3.room)).to(equal("sudokuRoom")) // We picked up the capitalization change
|
|
|
|
expect(user_groups_size(conf)).to(equal(2))
|
|
expect(user_groups_size_communities(conf)).to(equal(1))
|
|
expect(user_groups_size_legacy_groups(conf)).to(equal(1))
|
|
|
|
let legacyGroup5: UnsafeMutablePointer<ugroups_legacy_group_info>? = user_groups_get_legacy_group(conf2, &cDefinitelyRealId)
|
|
expect(ugroups_legacy_member_add(legacyGroup5, &cUsers[4], false)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup5, &cUsers[5], true)).to(beTrue())
|
|
expect(ugroups_legacy_member_add(legacyGroup5, &cUsers[6], true)).to(beTrue())
|
|
expect(ugroups_legacy_member_remove(legacyGroup5, &cUsers[1])).to(beTrue())
|
|
|
|
expect(config_needs_push(conf2)).to(beFalse())
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
|
|
let pushData9: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
expect(pushData9.pointee.seqno).to(equal(2))
|
|
expect(config_needs_dump(conf2)).to(beFalse())
|
|
pushData9.deallocate()
|
|
|
|
user_groups_set_free_legacy_group(conf2, legacyGroup5)
|
|
expect(config_needs_push(conf2)).to(beTrue())
|
|
expect(config_needs_dump(conf2)).to(beTrue())
|
|
|
|
var cCommunity4BaseUrl: [CChar] = "http://exAMple.ORG:5678".cArray.nullTerminated()
|
|
var cCommunity4Room: [CChar] = "sudokuROOM".cArray.nullTerminated()
|
|
user_groups_erase_community(conf2, &cCommunity4BaseUrl, &cCommunity4Room)
|
|
|
|
let fakeHash3: String = "fakehash3"
|
|
var cFakeHash3: [CChar] = fakeHash3.cArray.nullTerminated()
|
|
let pushData10: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
config_confirm_pushed(conf2, pushData10.pointee.seqno, &cFakeHash3)
|
|
|
|
expect(pushData10.pointee.seqno).to(equal(3))
|
|
expect([String](pointer: pushData10.pointee.obsolete, count: pushData10.pointee.obsolete_len))
|
|
.to(equal([fakeHash2]))
|
|
|
|
let currentHashes4: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
|
|
expect([String](pointer: currentHashes4?.pointee.value, count: currentHashes4?.pointee.len))
|
|
.to(equal([fakeHash3]))
|
|
currentHashes4?.deallocate()
|
|
|
|
var mergeHashes2: [UnsafePointer<CChar>?] = [cFakeHash3].unsafeCopy()
|
|
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData10.pointee.config)]
|
|
var mergeSize2: [Int] = [pushData10.pointee.config_len]
|
|
expect(config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)).to(equal(1))
|
|
|
|
expect(user_groups_size(conf)).to(equal(1))
|
|
expect(user_groups_size_communities(conf)).to(equal(0))
|
|
expect(user_groups_size_legacy_groups(conf)).to(equal(1))
|
|
|
|
var prio: Int32 = 0
|
|
var cBeanstalkBaseUrl: [CChar] = "http://jacksbeanstalk.org".cArray.nullTerminated()
|
|
var cBeanstalkPubkey: [UInt8] = Data(
|
|
hex: "0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff"
|
|
).cArray
|
|
|
|
["fee", "fi", "fo", "fum"].forEach { room in
|
|
var cRoom: [CChar] = room.cArray.nullTerminated()
|
|
prio += 1
|
|
|
|
var community4: ugroups_community_info = ugroups_community_info()
|
|
expect(user_groups_get_or_construct_community(conf, &community4, &cBeanstalkBaseUrl, &cRoom, &cBeanstalkPubkey))
|
|
.to(beTrue())
|
|
community4.priority = prio
|
|
user_groups_set_community(conf, &community4)
|
|
}
|
|
|
|
expect(user_groups_size(conf)).to(equal(5))
|
|
expect(user_groups_size_communities(conf)).to(equal(4))
|
|
expect(user_groups_size_legacy_groups(conf)).to(equal(1))
|
|
|
|
let fakeHash4: String = "fakehash4"
|
|
var cFakeHash4: [CChar] = fakeHash4.cArray.nullTerminated()
|
|
let pushData11: UnsafeMutablePointer<config_push_data> = config_push(conf)
|
|
config_confirm_pushed(conf, pushData11.pointee.seqno, &cFakeHash4)
|
|
expect(pushData11.pointee.seqno).to(equal(4))
|
|
expect([String](pointer: pushData11.pointee.obsolete, count: pushData11.pointee.obsolete_len))
|
|
.to(equal([fakeHash3, fakeHash2, fakeHash1]))
|
|
|
|
// Load some obsolete ones in just to check that they get immediately obsoleted
|
|
let fakeHash10: String = "fakehash10"
|
|
let cFakeHash10: [CChar] = fakeHash10.cArray.nullTerminated()
|
|
let fakeHash11: String = "fakehash11"
|
|
let cFakeHash11: [CChar] = fakeHash11.cArray.nullTerminated()
|
|
let fakeHash12: String = "fakehash12"
|
|
let cFakeHash12: [CChar] = fakeHash12.cArray.nullTerminated()
|
|
var mergeHashes3: [UnsafePointer<CChar>?] = [cFakeHash10, cFakeHash11, cFakeHash12, cFakeHash4].unsafeCopy()
|
|
var mergeData3: [UnsafePointer<UInt8>?] = [
|
|
UnsafePointer(pushData10.pointee.config),
|
|
UnsafePointer(pushData2.pointee.config),
|
|
UnsafePointer(pushData7.pointee.config),
|
|
UnsafePointer(pushData11.pointee.config)
|
|
]
|
|
var mergeSize3: [Int] = [
|
|
pushData10.pointee.config_len,
|
|
pushData2.pointee.config_len,
|
|
pushData7.pointee.config_len,
|
|
pushData11.pointee.config_len
|
|
]
|
|
expect(config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 4)).to(equal(4))
|
|
expect(config_needs_dump(conf2)).to(beTrue())
|
|
expect(config_needs_push(conf2)).to(beFalse())
|
|
pushData2.deallocate()
|
|
pushData7.deallocate()
|
|
pushData10.deallocate()
|
|
pushData11.deallocate()
|
|
|
|
let currentHashes5: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
|
|
expect([String](pointer: currentHashes5?.pointee.value, count: currentHashes5?.pointee.len))
|
|
.to(equal([fakeHash4]))
|
|
currentHashes5?.deallocate()
|
|
|
|
let pushData12: UnsafeMutablePointer<config_push_data> = config_push(conf2)
|
|
expect(pushData12.pointee.seqno).to(equal(4))
|
|
expect([String](pointer: pushData12.pointee.obsolete, count: pushData12.pointee.obsolete_len))
|
|
.to(equal([fakeHash11, fakeHash12, fakeHash10, fakeHash3]))
|
|
pushData12.deallocate()
|
|
|
|
for targetConf in [conf, conf2] {
|
|
// Iterate through and make sure we got everything we expected
|
|
var seen: [String] = []
|
|
|
|
var c1: ugroups_legacy_group_info = ugroups_legacy_group_info()
|
|
var c2: ugroups_community_info = ugroups_community_info()
|
|
let it: OpaquePointer = user_groups_iterator_new(targetConf)
|
|
|
|
while !user_groups_iterator_done(it) {
|
|
if user_groups_it_is_legacy_group(it, &c1) {
|
|
var memberCount: Int = 0
|
|
var adminCount: Int = 0
|
|
ugroups_legacy_members_count(&c1, &memberCount, &adminCount)
|
|
|
|
seen.append("legacy: \(String(libSessionVal: c1.name)), \(adminCount) admins, \(memberCount) members")
|
|
}
|
|
else if user_groups_it_is_community(it, &c2) {
|
|
seen.append("community: \(String(libSessionVal: c2.base_url))/r/\(String(libSessionVal: c2.room))")
|
|
}
|
|
else {
|
|
seen.append("unknown")
|
|
}
|
|
|
|
user_groups_iterator_advance(it)
|
|
}
|
|
|
|
user_groups_iterator_free(it)
|
|
|
|
expect(seen).to(equal([
|
|
"community: http://jacksbeanstalk.org/r/fee",
|
|
"community: http://jacksbeanstalk.org/r/fi",
|
|
"community: http://jacksbeanstalk.org/r/fo",
|
|
"community: http://jacksbeanstalk.org/r/fum",
|
|
"legacy: Englishmen, 3 admins, 2 members"
|
|
]))
|
|
}
|
|
}
|
|
}
|
|
}
|