Updated to the latest libSession

pull/941/head
Morgan Pretty 2 years ago
parent b47b98f2f8
commit 56a282846d

@ -1 +1 @@
Subproject commit 916a47fcd347332256b744457362639c405aebef
Subproject commit 6c4e38c4ed7f3a153428491bda588c782f8e0c60

@ -26,7 +26,7 @@
# request ever gets implemented: https://github.com/CocoaPods/CocoaPods/issues/8464
# Need to set the path or we won't find cmake
PATH=${PATH}:/usr/local/bin:/opt/homebrew/bin:/sbin/md5
PATH=${PATH}:/usr/local/bin:/opt/local/bin:/opt/homebrew/bin:/sbin/md5
exec 3>&1 # Save original stdout
@ -189,7 +189,8 @@ for i in "${!TARGET_ARCHS[@]}"; do
echo_message "Building ${TARGET_ARCHS[$i]} for $platform in $build"
cd "${SRCROOT}/LibSession-Util"
./utils/static-bundle.sh "$build" "" \
env -i PATH="$PATH" SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" \
./utils/static-bundle.sh "$build" "" \
-DCMAKE_TOOLCHAIN_FILE="${SRCROOT}/LibSession-Util/external/ios-cmake/ios.toolchain.cmake" \
-DPLATFORM=$platform \
-DDEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET \

@ -15,17 +15,17 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
let role: GroupMember.Role
let profile: Profile?
let accessibilityLabel: String?
let accessibilityId: String?
let accessibilityIdentifier: String?
}
private let threadId: String
private let threadVariant: SessionThread.Variant
private var originalName: String = ""
private var originalMembersAndZombieIds: Set<String> = []
private var originalMembersIds: Set<String> = []
private var name: String = ""
private var hasContactsToAdd: Bool = false
private var userSessionId: SessionId = .invalid
private var membersAndZombies: [GroupMemberDisplayInfo] = []
private var allGroupMembers: [GroupMemberDisplayInfo] = []
private var adminIds: Set<String> = []
private var isEditingGroupName = false { didSet { handleIsEditingGroupNameChanged() } }
private var tableViewHeightConstraint: NSLayoutConstraint!
@ -125,8 +125,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
)
.asRequest(of: GroupMemberDisplayInfo.self)
.fetchAll(db)
self?.membersAndZombies = allGroupMembers
.filter { $0.role == .standard || $0.role == .zombie }
self?.allGroupMembers = allGroupMembers
self?.adminIds = allGroupMembers
.filter { $0.role == .admin }
.map { $0.profileId }
@ -135,7 +134,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
let uniqueGroupMemberIds: Set<String> = allGroupMembers
.map { $0.profileId }
.asSet()
self?.originalMembersAndZombieIds = uniqueGroupMemberIds
self?.originalMembersIds = uniqueGroupMemberIds
self?.hasContactsToAdd = ((try? Profile
.allContactProfiles(
excluding: uniqueGroupMemberIds.inserting(userSessionId.hexString)
@ -214,16 +213,16 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
// MARK: - Table View Data Source / Delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return membersAndZombies.count
return allGroupMembers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: SessionCell = tableView.dequeue(type: SessionCell.self, for: indexPath)
let displayInfo: GroupMemberDisplayInfo = membersAndZombies[indexPath.row]
let displayInfo: GroupMemberDisplayInfo = allGroupMembers[indexPath.row]
cell.update(
with: SessionCell.Info(
id: displayInfo,
position: Position.with(indexPath.row, count: membersAndZombies.count),
position: Position.with(indexPath.row, count: allGroupMembers.count),
leftAccessory: .profile(id: displayInfo.profileId, profile: displayInfo.profile),
title: (
displayInfo.profile?.displayName() ??
@ -256,7 +255,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let profileId: String = self.membersAndZombies[indexPath.row].profileId
let profileId: String = self.allGroupMembers[indexPath.row].profileId
let delete: UIContextualAction = UIContextualAction(
title: "GROUP_ACTION_REMOVE".localized(),
@ -269,7 +268,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
tableView: tableView
) { [weak self] _, _, completionHandler in
self?.adminIds.remove(profileId)
self?.membersAndZombies.remove(at: indexPath.row)
self?.allGroupMembers.remove(at: indexPath.row)
self?.handleMembersChanged()
completionHandler(true)
@ -302,7 +301,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
}
private func handleMembersChanged() {
tableViewHeightConstraint.constant = CGFloat(membersAndZombies.count) * 78
tableViewHeightConstraint.constant = CGFloat(allGroupMembers.count) * 78
tableView.reloadData()
}
@ -364,7 +363,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
let userSessionId: SessionId = self.userSessionId
let userSelectionVC: UserSelectionVC = UserSelectionVC(
with: title,
excluding: membersAndZombies
excluding: allGroupMembers
.map { $0.profileId }
.asSet()
) { [weak self] selectedUserIds in
@ -378,10 +377,10 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
role: .standard,
profile: profile,
accessibilityLabel: "Contact",
accessibilityId: "Contact"
accessibilityIdentifier: "Contact"
)
}
self?.membersAndZombies = (self?.membersAndZombies ?? [])
self?.allGroupMembers = (self?.allGroupMembers ?? [])
.appending(contentsOf: selectedGroupMembers)
.sorted(by: { lhs, rhs in
if lhs.role == .zombie && rhs.role != .zombie {
@ -408,7 +407,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
})
.filter { $0.role == .standard || $0.role == .zombie }
let uniqueGroupMemberIds: Set<String> = (self?.membersAndZombies ?? [])
let uniqueGroupMemberIds: Set<String> = (self?.allGroupMembers ?? [])
.map { $0.profileId }
.asSet()
.inserting(contentsOf: self?.adminIds)
@ -443,16 +442,16 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
let threadId: String = self.threadId
let updatedName: String = self.name
let userSessionId: SessionId = self.userSessionId
let updatedMembers: [(String, Profile?)] = self.membersAndZombies
let updatedMembers: [(String, Profile?)] = self.allGroupMembers
.map { ($0.profileId, $0.profile) }
let updatedMemberIds: Set<String> = updatedMembers.map { $0.0 }.asSet()
guard updatedMemberIds != self.originalMembersAndZombieIds || updatedName != self.originalName else {
guard updatedMemberIds != self.originalMembersIds || updatedName != self.originalName else {
return popToConversationVC(self)
}
if !updatedMemberIds.contains(userSessionId.hexString) {
guard self.originalMembersAndZombieIds.removing(userSessionId.hexString) == updatedMemberIds else {
guard self.originalMembersIds.removing(userSessionId.hexString) == updatedMemberIds else {
return showError(
title: "GROUP_UPDATE_ERROR_TITLE".localized(),
message: "GROUP_UPDATE_ERROR_MESSAGE".localized()

@ -24,7 +24,7 @@ extension MessageReceiver {
groupIdentityPrivateKey: Data?,
name: String?,
authData: Data?,
created: Int64,
joinedAt: Int64,
invited: Bool,
calledFromConfigHandling: Bool,
using dependencies: Dependencies
@ -36,7 +36,7 @@ extension MessageReceiver {
let closedGroup: ClosedGroup = try ClosedGroup(
threadId: groupSessionId,
name: (name ?? "GROUP_TITLE_FALLBACK".localized()),
formationTimestamp: TimeInterval(created),
formationTimestamp: TimeInterval(joinedAt),
groupIdentityPrivateKey: groupIdentityPrivateKey,
authData: authData,
invited: invited
@ -50,7 +50,7 @@ extension MessageReceiver {
groupIdentityPrivateKey: groupIdentityPrivateKey,
name: name,
authData: authData,
joinedAt: created,
joinedAt: joinedAt,
invited: invited,
using: dependencies
)

@ -173,7 +173,6 @@ public final class MessageSender {
MessageWrapper.wrap(
type: .sessionMessage,
timestamp: sentTimestamp,
senderPublicKey: "",
base64EncodedContent: ciphertext.base64EncodedString()
)
)
@ -189,7 +188,6 @@ public final class MessageSender {
MessageWrapper.wrap(
type: .closedGroupMessage,
timestamp: sentTimestamp,
senderPublicKey: groupId,
base64EncodedContent: plaintext.base64EncodedString(),
wrapInWebSocketMessage: false
)
@ -223,7 +221,7 @@ public final class MessageSender {
MessageWrapper.wrap(
type: .closedGroupMessage,
timestamp: sentTimestamp,
senderPublicKey: groupPublicKey,
senderPublicKey: groupPublicKey, // Needed for Android
base64EncodedContent: ciphertext.base64EncodedString()
)
)

@ -96,8 +96,9 @@ internal extension SessionUtil {
.forEach { try $0.save(db) }
try GroupMember
.filter(GroupMember.Columns.groupId == groupSessionId.hexString)
.filter(
GroupMember.Columns.groupId == groupSessionId.hexString && (
(
GroupMember.Columns.role == GroupMember.Role.standard &&
!updatedStandardMemberIds.contains(GroupMember.Columns.profileId)
) || (

@ -425,10 +425,6 @@ internal extension SessionUtil {
.reduce(into: [:]) { result, next in result[next.id] = next }
try groups.forEach { group in
guard
let joinedAt: Int64 = group.joinedAt
else { return }
switch (existingGroups[group.groupSessionId], existingGroupSessionIds.contains(group.groupSessionId)) {
case (.none, _), (_, false):
// Add a new group if it doesn't already exist
@ -438,19 +434,24 @@ internal extension SessionUtil {
groupIdentityPrivateKey: group.groupIdentityPrivateKey,
name: group.name,
authData: group.authData,
created: Int64((group.joinedAt ?? (serverTimestampMs / 1000))),
joinedAt: Int64((group.joinedAt ?? (serverTimestampMs / 1000))),
invited: (group.invited == true),
calledFromConfigHandling: true,
using: dependencies
)
case (.some(let existingGroup), _):
let joinedAt: TimeInterval = (
group.joinedAt.map { TimeInterval($0) } ??
existingGroup.formationTimestamp
)
/// Otherwise update the existing group
///
/// **Note:** We ignore the `name` value here as if it's an existing group then assume we will get the
/// proper name by polling for the `GROUP_INFO` instead of via syncing the `USER_GROUPS` data
let groupChanges: [ConfigColumnAssignment] = [
(existingGroup.formationTimestamp == TimeInterval(joinedAt) ? nil :
(existingGroup.formationTimestamp == joinedAt ? nil :
ClosedGroup.Columns.formationTimestamp.set(to: TimeInterval(joinedAt))
),
(existingGroup.authData == group.authData ? nil :

@ -219,8 +219,9 @@ public extension SessionUtil {
.map { message -> [UInt8] in message.data.bytes }
.unsafeCopy()
var mergeSize: [Int] = messages.map { $0.data.count }
var mergedHashesPtr: UnsafeMutablePointer<config_string_list>?
try CExceptionHelper.performSafely {
config_merge(
mergedHashesPtr = config_merge(
conf,
&mergeHashes,
&mergeData,
@ -232,10 +233,23 @@ public extension SessionUtil {
mergeData.forEach { $0?.deallocate() }
// Get the list of hashes from the config (to determine which were successful)
let currentHashes: Set<String> = currentHashes().asSet()
let mergedHashes: [String] = mergedHashesPtr
.map { ptr in
[String](
pointer: ptr.pointee.value,
count: ptr.pointee.len,
defaultValue: []
)
}
.defaulting(to: [])
mergedHashesPtr?.deallocate()
if mergedHashes.count != messages.count {
SNLog("[SessionUtil] Unable to merge all \(messages[0].namespace) messages (\(mergedHashes.count)/\(messages.count))")
}
return messages
.filter { currentHashes.contains($0.serverHash) }
.filter { mergedHashes.contains($0.serverHash) }
.map { $0.serverTimestampMs }
.sorted()
.last

@ -1025,11 +1025,11 @@ public extension SessionThreadViewModel {
LEFT JOIN (
SELECT
\(groupMember[.groupId]),
COUNT(\(groupMember[.rowId])) AS \(ClosedGroupUserCount.Columns.closedGroupUserCount)
COUNT(DISTINCT \(groupMember[.profileId])) AS \(ClosedGroupUserCount.Columns.closedGroupUserCount)
FROM \(GroupMember.self)
WHERE (
\(SQL("\(groupMember[.groupId]) = \(threadId)")) AND
\(SQL("\(groupMember[.role]) = \(GroupMember.Role.standard)"))
\(SQL("\(groupMember[.role]) != \(GroupMember.Role.zombie)"))
)
) AS \(closedGroupUserCount) ON \(SQL("\(closedGroupUserCount[.groupId]) = \(threadId)"))

@ -25,7 +25,7 @@ public enum MessageWrapper {
public static func wrap(
type: SNProtoEnvelope.SNProtoEnvelopeType,
timestamp: UInt64,
senderPublicKey: String,
senderPublicKey: String = "", // FIXME: Remove once legacy groups are deprecated
base64EncodedContent: String,
wrapInWebSocketMessage: Bool = true
) throws -> Data {

@ -30,7 +30,6 @@ public struct ProfileManager {
private static let avatarTagLength: Int = 16
private static var profileAvatarCache: Atomic<[String: Data]> = Atomic([:])
private static var currentAvatarDownloads: Atomic<Set<String>> = Atomic([])
private static var downloadsToSchedule: Atomic<Set<DownloadInfo>> = Atomic([])
private static var scheduleDownloadsPublisher: AnyPublisher<Void, Never>?

@ -12,6 +12,8 @@ import Nimble
@testable import SessionMessagingKit
class LibSessionSpec: QuickSpec {
static let maxMessageSizeBytes: Int = 76800 // Storage server's limit, should match `config.hpp` in libSession
// FIXME: Would be good to move the identity generation into the libSession-util instead of using Sodium separately
static let userSeed: Data = Data(hex: "0123456789abcdef0123456789abcdef")
static let seed: Data = Data(
@ -164,7 +166,7 @@ fileprivate extension LibSessionSpec {
context("when checking error catching") {
// MARK: ---- it can catch size limit errors thrown when pushing
it("can catch size limit errors thrown when pushing") {
try (0..<10000).forEach { index in
try (0..<2500).forEach { index in
var contact: contacts_contact = try createContact(
for: index,
in: conf,
@ -174,7 +176,7 @@ fileprivate extension LibSessionSpec {
contacts_set(conf, &contact)
}
expect(contacts_size(conf)).to(equal(10000))
expect(contacts_size(conf)).to(equal(2500))
expect(config_needs_push(conf)).to(beTrue())
expect(config_needs_dump(conf)).to(beTrue())
@ -189,7 +191,7 @@ fileprivate extension LibSessionSpec {
context("when checking size limits") {
// MARK: ---- has not changed the max empty records
it("has not changed the max empty records") {
for index in (0..<100000) {
for index in (0..<2500) {
var contact: contacts_contact = try createContact(
for: index,
in: conf,
@ -210,7 +212,7 @@ fileprivate extension LibSessionSpec {
// MARK: ---- has not changed the max name only records
it("has not changed the max name only records") {
for index in (0..<100000) {
for index in (0..<2500) {
var contact: contacts_contact = try createContact(
for: index,
in: conf,
@ -232,7 +234,7 @@ fileprivate extension LibSessionSpec {
// MARK: ---- has not changed the max name and profile pic only records
it("has not changed the max name and profile pic only records") {
for index in (0..<100000) {
for index in (0..<2500) {
var contact: contacts_contact = try createContact(
for: index,
in: conf,
@ -254,7 +256,7 @@ fileprivate extension LibSessionSpec {
// MARK: ---- has not changed the max filled records
it("has not changed the max filled records") {
for index in (0..<100000) {
for index in (0..<2500) {
var contact: contacts_contact = try createContact(
for: index,
in: conf,
@ -417,9 +419,12 @@ fileprivate extension LibSessionSpec {
var mergeHashes: [UnsafePointer<CChar>?] = [cFakeHash2].unsafeCopy()
var mergeData: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData4.pointee.config)]
var mergeSize: [Int] = [pushData4.pointee.config_len]
expect(config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1)).to(equal(1))
let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1)
expect([String](pointer: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len))
.to(equal(["fakehash2"]))
config_confirm_pushed(conf2, pushData4.pointee.seqno, &cFakeHash2)
mergeHashes.forEach { $0?.deallocate() }
mergedHashes?.deallocate()
pushData4.deallocate()
expect(config_needs_push(conf)).to(beFalse())
@ -493,18 +498,24 @@ fileprivate extension LibSessionSpec {
var mergeHashes2: [UnsafePointer<CChar>?] = [cFakeHash3b].unsafeCopy()
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData7.pointee.config)]
var mergeSize2: [Int] = [pushData7.pointee.config_len]
expect(config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)).to(equal(1))
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)
expect([String](pointer: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash3b"]))
expect(config_needs_push(conf)).to(beTrue())
mergeHashes2.forEach { $0?.deallocate() }
mergedHashes2?.deallocate()
pushData7.deallocate()
var mergeHashes3: [UnsafePointer<CChar>?] = [cFakeHash3a].unsafeCopy()
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData6.pointee.config)]
var mergeSize3: [Int] = [pushData6.pointee.config_len]
expect(config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1)).to(equal(1))
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1)
expect([String](pointer: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash3a"]))
expect(config_needs_push(conf2)).to(beTrue())
mergeHashes2.forEach { $0?.deallocate() }
mergeHashes3.forEach { $0?.deallocate() }
mergedHashes3?.deallocate()
pushData6.deallocate()
pushData7.deallocate()
let pushData8: UnsafeMutablePointer<config_push_data> = config_push(conf)
expect(pushData8.pointee.seqno).to(equal(4))
@ -634,35 +645,32 @@ fileprivate extension LibSessionSpec {
// We don't need to push since we haven't changed anything, so this call is mainly just for
// testing:
let PROTOBUF_OVERHEAD: Int = 28 // To be removed once we no longer protobuf wrap this
let PROTOBUF_DATA_OFFSET: Int = 26
let PROTOBUF_OVERHEAD: Int = 176 // To be removed once we no longer protobuf wrap this
let pushData1: UnsafeMutablePointer<config_push_data> = config_push(conf)
expect(pushData1.pointee).toNot(beNil())
expect(pushData1.pointee.seqno).to(equal(0))
expect(pushData1.pointee.config_len).to(equal(256 + PROTOBUF_OVERHEAD))
let encDomain: [CChar] = "UserProfile"
.bytes
.map { CChar(bitPattern: $0) }
expect(String(cString: config_encryption_domain(conf))).to(equal("UserProfile"))
var toPushDecSize: Int = 0
let toPushDecrypted: UnsafeMutablePointer<UInt8>? = config_decrypt(
pushData1.pointee.config.advanced(by: PROTOBUF_DATA_OFFSET),
(pushData1.pointee.config_len - PROTOBUF_OVERHEAD),
userEdSK,
encDomain,
&toPushDecSize
)
let prefixPadding: String = (0..<193)
.map { _ in "\0" }
.joined()
expect(toPushDecrypted).toNot(beNil())
expect(toPushDecSize).to(equal(216)) // 256 - 40 overhead
expect(String(pointer: toPushDecrypted, length: toPushDecSize))
.to(equal("\(prefixPadding)d1:#i0e1:&de1:<le1:=dee"))
// There's nothing particularly profound about this value (it is multiple layers of nested
// protobuf with some encryption and padding halfway through); this test is just here to ensure
// that our pushed messages are deterministic:
let expectedPushData1: Data = Data(hex: [
"080112ab030a0012001aa20308062801429b0326ec9746282053eb119228e6c36012966e7d2642163169ba39" +
"98af44ca65f967768dd78ee80fffab6f809f6cef49c73a36c82a89622ff0de2ceee06b8c638e2c876fa9047f" +
"449dbe24b1fc89281a264fe90abdeffcdd44f797bd4572a6c5ae8d88bf372c3c717943ebd570222206fabf0e" +
"e9f3c6756f5d71a32616b1df53d12887961f5c129207a79622ccc1a4bba976886d9a6ddf0fe5d570e5075d01" +
"ecd627f656e95f27b4c40d5661b5664cedd3e568206effa1308b0ccd663ca61a6d39c0731891804a8cf5edcf" +
"8b98eaa5580c3d436e22156e38455e403869700956c3c1dd0b4470b663e75c98c5b859b53ccef6559215d804" +
"9f755be9c2d6b3f4a310f97c496fc392f65b6431dd87788ac61074fd8cd409702e1b839b3f774d38cf8b28f0" +
"226c4efa5220ac6ae060793e36e7ef278d42d042f15b21291f3bb29e3158f09d154b93f83fd8a319811a26cb" +
"5240d90cbb360fafec0b7eff4c676ae598540813d062dc9468365c73b4cfa2ffd02d48cdcd8f0c71324c6d0a" +
"60346a7a0e50af3be64684b37f9e6c831115bf112ddd18acde08eaec376f0872a3952000"
].joined())
expect(Data(bytes: pushData1.pointee.config, count: pushData1.pointee.config_len))
.to(equal(expectedPushData1))
pushData1.deallocate()
toPushDecrypted?.deallocate()
// This should also be unset:
let pic: user_profile_pic = user_profile_get_pic(conf)
@ -741,34 +749,6 @@ fileprivate extension LibSessionSpec {
"49bf122762d7bc1d6d9c02f6d54f8384"
].joined()).bytes
let pushData2Str: String = String(
pointer: pushData2.pointee.config.advanced(by: PROTOBUF_DATA_OFFSET),
length: (pushData2.pointee.config_len - PROTOBUF_OVERHEAD),
encoding: .ascii
)!
let expPush1EncryptedStr: String = String(pointer: expPush1Encrypted, length: expPush1Encrypted.count, encoding: .ascii)!
expect(pushData2Str).to(equal(expPush1EncryptedStr))
// Raw decryption doesn't unpad (i.e. the padding is part of the encrypted data)
var pushData2DecSize: Int = 0
let pushData2Decrypted: UnsafeMutablePointer<UInt8>? = config_decrypt(
pushData2.pointee.config.advanced(by: PROTOBUF_DATA_OFFSET),
(pushData2.pointee.config_len - PROTOBUF_OVERHEAD),
userEdSK,
encDomain,
&pushData2DecSize
)
let prefixPadding2: String = (0..<(256 - 40 - expPush1Decrypted.count))
.map { _ in "\0" }
.joined()
expect(pushData2DecSize).to(equal(216)) // 256 - 40 overhead
let pushData2DecryptedStr: String = String(pointer: pushData2Decrypted, length: pushData2DecSize, encoding: .ascii)!
let expPush1DecryptedStr: String = String(pointer: expPush1Decrypted, length: expPush1Decrypted.count, encoding: .ascii)
.map { "\(prefixPadding2)\($0)" }!
expect(pushData2DecryptedStr).to(equal(expPush1DecryptedStr))
pushData2Decrypted?.deallocate()
// We haven't dumped, so still need to dump:
expect(config_needs_dump(conf)).to(beTrue())
// We did call push, but we haven't confirmed it as stored yet, so this will still return true:
@ -851,14 +831,16 @@ fileprivate extension LibSessionSpec {
expect(user_profile_init(&conf2, &userEdSK, nil, 0, &error2)).to(equal(0))
expect(config_needs_dump(conf2)).to(beFalse())
// Now imagine we just pulled down the `exp_push1` string from the swarm; we merge it into
// conf2:
// Now imagine we just pulled down the encrypted string from the swarm; we merge it into conf2:
var mergeHashes: [UnsafePointer<CChar>?] = [cFakeHash1].unsafeCopy()
var mergeData: [UnsafePointer<UInt8>?] = [expPush1Encrypted].unsafeCopy()
var mergeSize: [Int] = [expPush1Encrypted.count]
expect(config_merge(conf2, &mergeHashes, &mergeData, &mergeSize, 1)).to(equal(1))
let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes, &mergeData, &mergeSize, 1)
expect([String](pointer: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len))
.to(equal(["fakehash1"]))
mergeHashes.forEach { $0?.deallocate() }
mergeData.forEach { $0?.deallocate() }
mergedHashes?.deallocate()
// Our state has changed, so we need to dump:
expect(config_needs_dump(conf2)).to(beTrue())
@ -937,12 +919,21 @@ fileprivate extension LibSessionSpec {
var mergeHashes2: [UnsafePointer<CChar>?] = [cFakeHash2].unsafeCopy()
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)]
var mergeSize2: [Int] = [pushData3.pointee.config_len]
expect(config_merge(conf2, &mergeHashes2, &mergeData2, &mergeSize2, 1)).to(equal(1))
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes2, &mergeData2, &mergeSize2, 1)
expect([String](pointer: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash2"]))
mergeHashes2.forEach { $0?.deallocate() }
mergedHashes2?.deallocate()
pushData3.deallocate()
var mergeHashes3: [UnsafePointer<CChar>?] = [cFakeHash3].unsafeCopy()
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData4.pointee.config)]
var mergeSize3: [Int] = [pushData4.pointee.config_len]
expect(config_merge(conf, &mergeHashes3, &mergeData3, &mergeSize3, 1)).to(equal(1))
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes3, &mergeData3, &mergeSize3, 1)
expect([String](pointer: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash3"]))
mergeHashes3.forEach { $0?.deallocate() }
mergedHashes3?.deallocate()
pushData4.deallocate()
// Now after the merge we *will* want to push from both client, since both will have generated a
@ -1157,8 +1148,12 @@ fileprivate extension LibSessionSpec {
var mergeHashes: [UnsafePointer<CChar>?] = [cFakeHash2].unsafeCopy()
var mergeData: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)]
var mergeSize: [Int] = [pushData2.pointee.config_len]
expect(config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1)).to(equal(1))
let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1)
expect([String](pointer: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len))
.to(equal(["fakehash2"]))
config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash2)
mergeHashes.forEach { $0?.deallocate() }
mergedHashes?.deallocate()
pushData2.deallocate()
expect(config_needs_push(conf)).to(beFalse())
@ -1594,7 +1589,11 @@ fileprivate extension LibSessionSpec {
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))
let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes1, &mergeData1, &mergeSize1, 1)
expect([String](pointer: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len))
.to(equal(["fakehash2"]))
mergeHashes1.forEach { $0?.deallocate() }
mergedHashes1?.deallocate()
pushData8.deallocate()
var cCommunity3BaseUrl: [CChar] = "http://example.org:5678".cArray.nullTerminated()
@ -1647,7 +1646,11 @@ fileprivate extension LibSessionSpec {
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))
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)
expect([String](pointer: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash3"]))
mergeHashes2.forEach { $0?.deallocate() }
mergedHashes2?.deallocate()
expect(user_groups_size(conf)).to(equal(1))
expect(user_groups_size_communities(conf)).to(equal(0))
@ -1702,9 +1705,13 @@ fileprivate extension LibSessionSpec {
pushData7.pointee.config_len,
pushData11.pointee.config_len
]
expect(config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 4)).to(equal(4))
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 4)
expect([String](pointer: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash10", "fakehash11", "fakehash12", "fakehash4"]))
expect(config_needs_dump(conf2)).to(beTrue())
expect(config_needs_push(conf2)).to(beFalse())
mergeHashes3.forEach { $0?.deallocate() }
mergedHashes3?.deallocate()
pushData2.deallocate()
pushData7.deallocate()
pushData10.deallocate()
@ -1825,9 +1832,12 @@ fileprivate extension LibSessionSpec {
var mergeHashes1: [UnsafePointer<CChar>?] = [cFakeHash1].unsafeCopy()
var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData1.pointee.config)]
var mergeSize1: [Int] = [pushData1.pointee.config_len]
expect(config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1)).to(equal(1))
let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1)
expect([String](pointer: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len))
.to(equal(["fakehash1"]))
expect(config_needs_push(conf2)).to(beFalse())
mergeHashes1.forEach { $0?.deallocate() }
mergedHashes1?.deallocate()
pushData1.deallocate()
let namePtr: UnsafePointer<CChar>? = groups_info_get_name(conf2)
@ -1867,8 +1877,11 @@ fileprivate extension LibSessionSpec {
var mergeHashes2: [UnsafePointer<CChar>?] = [cFakeHash2].unsafeCopy()
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)]
var mergeSize2: [Int] = [pushData2.pointee.config_len]
expect(config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)).to(equal(1))
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)
expect([String](pointer: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash2"]))
mergeHashes2.forEach { $0?.deallocate() }
mergedHashes2?.deallocate()
expect(config_needs_push(conf)).to(beTrue())
@ -1896,8 +1909,11 @@ fileprivate extension LibSessionSpec {
var mergeHashes3: [UnsafePointer<CChar>?] = [cFakeHash3].unsafeCopy()
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)]
var mergeSize3: [Int] = [pushData3.pointee.config_len]
expect(config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1)).to(equal(1))
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1)
expect([String](pointer: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash3"]))
mergeHashes3.forEach { $0?.deallocate() }
mergedHashes3?.deallocate()
pushData3.deallocate()
let namePtr3: UnsafePointer<CChar>? = groups_info_get_name(conf2)
@ -1991,7 +2007,7 @@ fileprivate extension LibSessionSpec {
it("can catch size limit errors thrown when pushing") {
var randomGenerator: ARC4RandomNumberGenerator = ARC4RandomNumberGenerator(seed: 1000)
try (0..<10000).forEach { index in
try (0..<2500).forEach { index in
var member: config_group_member = try createMember(
for: index,
in: conf,
@ -2001,7 +2017,7 @@ fileprivate extension LibSessionSpec {
groups_members_set(conf, &member)
}
expect(groups_members_size(conf)).to(equal(10000))
expect(groups_members_size(conf)).to(equal(2500))
expect(config_needs_push(conf)).to(beTrue())
expect(config_needs_dump(conf)).to(beTrue())
@ -2018,7 +2034,7 @@ fileprivate extension LibSessionSpec {
it("has not changed the max empty records") {
var randomGenerator: ARC4RandomNumberGenerator = ARC4RandomNumberGenerator(seed: 1000)
for index in (0..<100000) {
for index in (0..<2500) {
var member: config_group_member = try createMember(
for: index,
in: conf,
@ -2041,7 +2057,7 @@ fileprivate extension LibSessionSpec {
it("has not changed the max name only records") {
var randomGenerator: ARC4RandomNumberGenerator = ARC4RandomNumberGenerator(seed: 1000)
for index in (0..<100000) {
for index in (0..<2500) {
var member: config_group_member = try createMember(
for: index,
in: conf,
@ -2065,7 +2081,7 @@ fileprivate extension LibSessionSpec {
it("has not changed the max name and profile pic only records") {
var randomGenerator: ARC4RandomNumberGenerator = ARC4RandomNumberGenerator(seed: 1000)
for index in (0..<100000) {
for index in (0..<2500) {
var member: config_group_member = try createMember(
for: index,
in: conf,
@ -2089,7 +2105,7 @@ fileprivate extension LibSessionSpec {
it("has not changed the max filled records") {
var randomGenerator: ARC4RandomNumberGenerator = ARC4RandomNumberGenerator(seed: 1000)
for index in (0..<100000) {
for index in (0..<2500) {
var member: config_group_member = try createMember(
for: index,
in: conf,
@ -2185,9 +2201,12 @@ fileprivate extension LibSessionSpec {
var mergeHashes1: [UnsafePointer<CChar>?] = [cFakeHash1].unsafeCopy()
var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData1.pointee.config)]
var mergeSize1: [Int] = [pushData1.pointee.config_len]
expect(config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1)).to(equal(1))
let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1)
expect([String](pointer: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len))
.to(equal(["fakehash1"]))
expect(config_needs_push(conf2)).to(beFalse())
mergeHashes1.forEach { $0?.deallocate() }
mergedHashes1?.deallocate()
pushData1.deallocate()
expect(groups_members_size(conf2)).to(equal(25))
@ -2284,8 +2303,11 @@ fileprivate extension LibSessionSpec {
var mergeHashes2: [UnsafePointer<CChar>?] = [cFakeHash2].unsafeCopy()
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)]
var mergeSize2: [Int] = [pushData2.pointee.config_len]
expect(config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)).to(equal(1))
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1)
expect([String](pointer: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash2"]))
mergeHashes2.forEach { $0?.deallocate() }
mergedHashes2?.deallocate()
var cSessionId2: [CChar] = sids[23].cArray
var member2: config_group_member = config_group_member()
@ -2429,9 +2451,12 @@ fileprivate extension LibSessionSpec {
var mergeHashes3: [UnsafePointer<CChar>?] = [cFakeHash3].unsafeCopy()
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)]
var mergeSize3: [Int] = [pushData3.pointee.config_len]
expect(config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1)).to(equal(1))
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1)
expect([String](pointer: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash3"]))
mergeHashes3.forEach { $0?.deallocate() }
mergedHashes3?.deallocate()
expect(groups_members_size(conf2)).to(equal(44)) // 18 deleted earlier
(0..<62).forEach { index in
@ -2592,6 +2617,75 @@ fileprivate extension LibSessionSpec {
class func groupKeysSpec() {
context("GROUP_KEYS") {
@TestState var userEdSK: [UInt8]! = LibSessionSpec.userEdSK
@TestState var edPK: [UInt8]! = LibSessionSpec.edPK
@TestState var edSK: [UInt8]! = LibSessionSpec.edSK
@TestState var error: [CChar]! = [CChar](repeating: 0, count: 256)
@TestState var infoConf: UnsafeMutablePointer<config_object>?
@TestState var membersConf: UnsafeMutablePointer<config_object>?
@TestState var keysConf: UnsafeMutablePointer<config_group_keys>?
@TestState var infoInitResult: Int32! = {
groups_info_init(&infoConf, &edPK, &edSK, nil, 0, &error)
}()
@TestState var membersInitResult: Int32! = {
groups_members_init(&membersConf, &edPK, &edSK, nil, 0, &error)
}()
@TestState var keysInitResult: Int32! = {
LibSessionSpec.initKeysConf(&keysConf, &infoConf, &membersConf)
}()
@TestState var membersConf2: UnsafeMutablePointer<config_object>?
@TestState var keysConf2: UnsafeMutablePointer<config_group_keys>?
@TestState var membersInitResult2: Int32! = {
groups_members_init(&membersConf2, &edPK, &edSK, nil, 0, &error)
}()
@TestState var keysInitResult2: Int32! = {
LibSessionSpec.initKeysConf(&keysConf2, &infoConf, &membersConf2)
}()
@TestState var numRecords: Int! = 0
// Convenience
var conf: UnsafeMutablePointer<config_group_keys>? { keysConf }
var conf2: UnsafeMutablePointer<config_group_keys>? { keysConf2 }
// MARK: - when checking error catching
context("when checking error catching") {
// MARK: -- does not throw size exceptions when generating
it("does not throw size exceptions when generating") {
var randomGenerator: ARC4RandomNumberGenerator = ARC4RandomNumberGenerator(seed: 1000)
var pushResultLen: Int = 0
// It's actually the number of members which can cause the keys message to get too large so
// start by generating too many members
try (0..<1750).forEach { index in
var member: config_group_member = try createMember(
for: index,
in: membersConf,
rand: &randomGenerator,
maxing: .allProperties
)
groups_members_set(membersConf, &member)
}
expect {
try CExceptionHelper.performSafely {
var pushResult: UnsafePointer<UInt8>? = nil
expect(groups_keys_rekey(
conf,
infoConf,
membersConf,
&pushResult,
&pushResultLen
)).to(beTrue())
}
}
.toNot(throwError(NSError(domain: "cpp_exception", code: -2, userInfo: ["NSLocalizedDescription": "Config data is too large"])))
expect(pushResultLen).to(beGreaterThan(LibSessionSpec.maxMessageSizeBytes))
expect(groups_keys_needs_dump(conf)).to(beTrue())
}
}
// MARK: -- generates config correctly
it("generates config correctly") {
let userSeed: Data = Data(hex: "0123456789abcdef0123456789abcdef")

Loading…
Cancel
Save