mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge branch 'dev' into light-mode
This commit is contained in:
commit
36277ea090
16 changed files with 123 additions and 57 deletions
|
@ -4100,7 +4100,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
|
@ -4114,7 +4114,7 @@
|
|||
INFOPLIST_FILE = SignalShareExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -4162,7 +4162,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
@ -4181,7 +4181,7 @@
|
|||
INFOPLIST_FILE = SignalShareExtension/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -4216,7 +4216,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
|
@ -4235,7 +4235,7 @@
|
|||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.utilities";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
|
@ -4286,7 +4286,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
|
@ -4310,7 +4310,7 @@
|
|||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.utilities";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
|
@ -4348,7 +4348,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
|
@ -4360,7 +4360,7 @@
|
|||
INFOPLIST_FILE = LokiPushNotificationService/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service";
|
||||
|
@ -4411,7 +4411,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
@ -4428,7 +4428,7 @@
|
|||
INFOPLIST_FILE = LokiPushNotificationService/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service";
|
||||
|
@ -4612,7 +4612,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -4647,7 +4647,7 @@
|
|||
"$(SRCROOT)",
|
||||
);
|
||||
LLVM_LTO = NO;
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
|
||||
|
@ -4680,7 +4680,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 106;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -4715,7 +4715,7 @@
|
|||
"$(SRCROOT)",
|
||||
);
|
||||
LLVM_LTO = NO;
|
||||
MARKETING_VERSION = 1.4.6;
|
||||
MARKETING_VERSION = 1.4.7;
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
|
||||
PRODUCT_NAME = Session;
|
||||
|
|
|
@ -174,7 +174,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat
|
|||
guard selectedContacts.count >= 1 else {
|
||||
return showError(title: "Please pick at least 1 group member")
|
||||
}
|
||||
guard selectedContacts.count < 50 else { // Minus one because we're going to include self later
|
||||
guard selectedContacts.count < ClosedGroupsProtocol.groupSizeLimit else { // Minus one because we're going to include self later
|
||||
return showError(title: NSLocalizedString("vc_create_closed_group_too_many_group_members_error", comment: ""))
|
||||
}
|
||||
let selectedContacts = self.selectedContacts
|
||||
|
|
|
@ -195,7 +195,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
timestampLabelText
|
||||
= NSLocalizedString(@"MESSAGE_STATUS_SEND_FAILED", @"Label indicating that a message failed to send.");
|
||||
} else {
|
||||
timestampLabelText = [DateUtil formatMessageTimestamp:viewItem.interaction.timestamp];
|
||||
timestampLabelText = [DateUtil formatMessageTimestamp:viewItem.interaction.timestampForUI];
|
||||
}
|
||||
|
||||
TSMessage *message = [viewItem.interaction as:TSMessage.class];
|
||||
|
|
|
@ -4683,7 +4683,7 @@ typedef enum : NSUInteger {
|
|||
OWSAssertDebug(left <= mid);
|
||||
OWSAssertDebug(mid < right);
|
||||
id<ConversationViewItem> viewItem = self.viewItems[mid];
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
if (viewItem.interaction.timestampForUI >= viewHorizonTimestamp) {
|
||||
right = mid;
|
||||
} else {
|
||||
// This is an optimization; it also ensures that we converge.
|
||||
|
@ -4692,7 +4692,7 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
OWSAssertDebug(left == right);
|
||||
id<ConversationViewItem> viewItem = self.viewItems[left];
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
if (viewItem.interaction.timestampForUI >= viewHorizonTimestamp) {
|
||||
OWSLogInfo(@"firstIndexPathAtViewHorizonTimestamp: %zd / %zd", left, self.viewItems.count);
|
||||
return [NSIndexPath indexPathForRow:(NSInteger) left inSection:0];
|
||||
} else {
|
||||
|
@ -5402,7 +5402,7 @@ typedef enum : NSUInteger {
|
|||
__block TSInteraction *targetInteraction;
|
||||
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.thread enumerateInteractionsWithTransaction:transaction usingBlock:^(TSInteraction *interaction, YapDatabaseReadTransaction *t) {
|
||||
if (interaction.timestamp == timestamp.unsignedLongLongValue) {
|
||||
if (interaction.timestampForUI == timestamp.unsignedLongLongValue) {
|
||||
targetInteraction = interaction;
|
||||
}
|
||||
}];
|
||||
|
@ -5426,7 +5426,7 @@ typedef enum : NSUInteger {
|
|||
{
|
||||
__block TSInteraction *targetInteraction;
|
||||
[self.thread enumerateInteractionsUsingBlock:^(TSInteraction *interaction) {
|
||||
if (interaction.timestamp == timestamp.unsignedLongLongValue) {
|
||||
if (interaction.timestampForUI == timestamp.unsignedLongLongValue) {
|
||||
targetInteraction = interaction;
|
||||
}
|
||||
}];
|
||||
|
|
|
@ -1350,7 +1350,7 @@ static const int kYapDatabaseRangeMaxLength = 25000;
|
|||
break;
|
||||
}
|
||||
|
||||
uint64_t viewItemTimestamp = viewItem.interaction.timestamp;
|
||||
uint64_t viewItemTimestamp = viewItem.interaction.timestampForUI;
|
||||
OWSAssertDebug(viewItemTimestamp > 0);
|
||||
|
||||
BOOL shouldShowDate = NO;
|
||||
|
@ -1417,7 +1417,7 @@ static const int kYapDatabaseRangeMaxLength = 25000;
|
|||
NSAttributedString *_Nullable senderName = nil;
|
||||
|
||||
OWSInteractionType interactionType = viewItem.interaction.interactionType;
|
||||
NSString *timestampText = [DateUtil formatTimestampShort:viewItem.interaction.timestamp];
|
||||
NSString *timestampText = [DateUtil formatTimestampShort:viewItem.interaction.timestampForUI];
|
||||
|
||||
if (interactionType == OWSInteractionType_OutgoingMessage) {
|
||||
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
|
||||
|
|
|
@ -683,22 +683,25 @@ const CGFloat kIconViewLength = 24;
|
|||
[weakSelf showGroupMembersView];
|
||||
}]
|
||||
];
|
||||
[mainSection addItem:[OWSTableItem
|
||||
itemWithCustomCellBlock:^{
|
||||
UITableViewCell *cell =
|
||||
[weakSelf disclosureCellWithName:NSLocalizedString(@"LEAVE_GROUP_ACTION",
|
||||
@"table cell label in conversation settings")
|
||||
iconName:@"table_ic_group_leave"
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(
|
||||
OWSConversationSettingsViewController, @"leave_group")];
|
||||
cell.userInteractionEnabled = !weakSelf.hasLeftGroup;
|
||||
NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
|
||||
if ([((TSGroupThread *)self.thread).groupModel.groupMemberIds containsObject:userPublicKey]) {
|
||||
[mainSection addItem:[OWSTableItem
|
||||
itemWithCustomCellBlock:^{
|
||||
UITableViewCell *cell =
|
||||
[weakSelf disclosureCellWithName:NSLocalizedString(@"LEAVE_GROUP_ACTION",
|
||||
@"table cell label in conversation settings")
|
||||
iconName:@"table_ic_group_leave"
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(
|
||||
OWSConversationSettingsViewController, @"leave_group")];
|
||||
cell.userInteractionEnabled = !weakSelf.hasLeftGroup;
|
||||
|
||||
return cell;
|
||||
}
|
||||
actionBlock:^{
|
||||
[weakSelf didTapLeaveGroup];
|
||||
}]
|
||||
];
|
||||
return cell;
|
||||
}
|
||||
actionBlock:^{
|
||||
[weakSelf didTapLeaveGroup];
|
||||
}]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
+ (void)processIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)incomingSentMessageTranscript
|
||||
serverID:(uint64_t)serverID
|
||||
serverTimestamp:(uint64_t)serverTimestamp
|
||||
attachmentHandler:(void (^)(
|
||||
NSArray<TSAttachmentStream *> *attachmentStreams))attachmentHandler
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
|
|
@ -62,6 +62,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
+ (void)processIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)transcript
|
||||
serverID:(uint64_t)serverID
|
||||
serverTimestamp:(uint64_t)serverTimestamp
|
||||
attachmentHandler:(void (^)(
|
||||
NSArray<TSAttachmentStream *> *attachmentStreams))attachmentHandler
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
|
@ -104,6 +105,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
contactShare:transcript.contact
|
||||
linkPreview:transcript.linkPreview];
|
||||
|
||||
|
||||
if (transcript.thread.isGroupThread) {
|
||||
TSGroupThread *thread = (TSGroupThread *)transcript.thread;
|
||||
if (thread.isPublicChat) {
|
||||
[outgoingMessage setServerTimestampToReceivedTimestamp:serverTimestamp];
|
||||
}
|
||||
}
|
||||
|
||||
if (serverID != 0) {
|
||||
outgoingMessage.openGroupServerMessageID = serverID;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,6 @@ public enum OnionRequestAPI {
|
|||
public static var guardSnodes: Set<Snode> = []
|
||||
public static var paths: [Path] = [] // Not a set to ensure we consistently show the same path to the user
|
||||
|
||||
private static var snodePool: Set<Snode> {
|
||||
let unreliableSnodes = Set(SnodeAPI.snodeFailureCount.keys)
|
||||
return SnodeAPI.snodePool.subtracting(unreliableSnodes)
|
||||
}
|
||||
|
||||
// MARK: Settings
|
||||
/// The number of snodes (including the guard snode) in a path.
|
||||
private static let pathSize: UInt = 3
|
||||
|
@ -84,7 +79,7 @@ public enum OnionRequestAPI {
|
|||
} else {
|
||||
print("[Loki] [Onion Request API] Populating guard snode cache.")
|
||||
return SnodeAPI.getRandomSnode().then2 { _ -> Promise<Set<Snode>> in // Just used to populate the snode pool
|
||||
var unusedSnodes = snodePool // Sync on LokiAPI.workQueue
|
||||
var unusedSnodes = SnodeAPI.snodePool // Sync on LokiAPI.workQueue
|
||||
guard unusedSnodes.count >= guardSnodeCount else { throw Error.insufficientSnodes }
|
||||
func getGuardSnode() -> Promise<Snode> {
|
||||
// randomElement() uses the system's default random generator, which is cryptographically secure
|
||||
|
@ -115,7 +110,7 @@ public enum OnionRequestAPI {
|
|||
}
|
||||
return SnodeAPI.getRandomSnode().then2 { _ -> Promise<[Path]> in // Just used to populate the snode pool
|
||||
return getGuardSnodes().map2 { guardSnodes -> [Path] in
|
||||
var unusedSnodes = snodePool.subtracting(guardSnodes)
|
||||
var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes)
|
||||
let pathSnodeCount = guardSnodeCount * pathSize - guardSnodeCount
|
||||
guard unusedSnodes.count >= pathSnodeCount else { throw Error.insufficientSnodes }
|
||||
// Don't test path snodes as this would reveal the user's IP to them
|
||||
|
@ -290,8 +285,7 @@ public enum OnionRequestAPI {
|
|||
let url = "\(guardSnode.address):\(guardSnode.port)/onion_req"
|
||||
let finalEncryptionResult = intermediate.finalEncryptionResult
|
||||
let onion = finalEncryptionResult.ciphertext
|
||||
let requestSizeLimit = Double(FileServerAPI.maxFileSize) / FileServerAPI.fileSizeORMultiplier
|
||||
if case Destination.server = destination, Double(onion.count) > 0.75 * requestSizeLimit {
|
||||
if case Destination.server = destination, Double(onion.count) > 0.75 * Double(FileServerAPI.maxFileSize) {
|
||||
print("[Loki] Approaching request size limit: ~\(onion.count) bytes.")
|
||||
}
|
||||
let parameters: JSON = [
|
||||
|
@ -339,7 +333,13 @@ public enum OnionRequestAPI {
|
|||
}
|
||||
}
|
||||
promise.catch2 { error in // Must be invoked on LokiAPI.workQueue
|
||||
guard case HTTP.Error.httpRequestFailed(_, _) = error else { return }
|
||||
guard case HTTP.Error.httpRequestFailed(let statusCode, let json) = error else { return }
|
||||
// Marking all the snodes in the path as unreliable here is aggressive, but otherwise users
|
||||
// can get stuck with a failing path that just refreshes to the same path.
|
||||
let path = paths.first { $0.contains(guardSnode) }
|
||||
path?.forEach { snode in
|
||||
SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw
|
||||
}
|
||||
dropAllPaths() // A snode in the path is bad; retry with a different path
|
||||
dropGuardSnode(guardSnode)
|
||||
}
|
||||
|
|
|
@ -174,6 +174,7 @@ public final class PublicChatPoller : NSObject {
|
|||
envelope.setSource(senderPublicKey)
|
||||
envelope.setSourceDevice(OWSDevicePrimaryDeviceId)
|
||||
envelope.setContent(try! content.build().serializedData())
|
||||
envelope.setServerTimestamp(message.serverTimestamp)
|
||||
try! Storage.writeSync { transaction in
|
||||
transaction.setObject(senderDisplayName, forKey: senderPublicKey, inCollection: publicChat.id)
|
||||
let messageServerID = message.serverID
|
||||
|
|
|
@ -15,10 +15,10 @@ public final class SnodeAPI : NSObject {
|
|||
|
||||
// MARK: Settings
|
||||
private static let maxRetryCount: UInt = 4
|
||||
private static let minimumSnodePoolCount = 32
|
||||
private static let minimumSnodePoolCount = 64
|
||||
private static let minimumSwarmSnodeCount = 2
|
||||
private static let seedNodePool: Set<String> = [ "https://storage.seed1.loki.network", "https://storage.seed3.loki.network", "https://public.loki.foundation" ]
|
||||
private static let snodeFailureThreshold = 2
|
||||
private static let snodeFailureThreshold = 1
|
||||
private static let targetSwarmSnodeCount = 2
|
||||
|
||||
internal static var powDifficulty: UInt = 1
|
||||
|
@ -296,7 +296,7 @@ public final class SnodeAPI : NSObject {
|
|||
|
||||
// MARK: Error Handling
|
||||
/// - Note: Should only be invoked from `LokiAPI.workQueue` to avoid race conditions.
|
||||
internal static func handleError(withStatusCode statusCode: UInt, json: JSON?, forSnode snode: Snode, associatedWith publicKey: String) -> Error? {
|
||||
internal static func handleError(withStatusCode statusCode: UInt, json: JSON?, forSnode snode: Snode, associatedWith publicKey: String? = nil) -> Error? {
|
||||
#if DEBUG
|
||||
assertOnQueue(SnodeAPI.workQueue)
|
||||
#endif
|
||||
|
@ -307,8 +307,11 @@ public final class SnodeAPI : NSObject {
|
|||
print("[Loki] Couldn't reach snode at: \(snode); setting failure count to \(newFailureCount).")
|
||||
if newFailureCount >= SnodeAPI.snodeFailureThreshold {
|
||||
print("[Loki] Failure threshold reached for: \(snode); dropping it.")
|
||||
SnodeAPI.dropSnodeFromSwarmIfNeeded(snode, publicKey: publicKey)
|
||||
if let publicKey = publicKey {
|
||||
SnodeAPI.dropSnodeFromSwarmIfNeeded(snode, publicKey: publicKey)
|
||||
}
|
||||
SnodeAPI.dropSnodeFromSnodePool(snode)
|
||||
print("[Loki] Snode pool count: \(snodePool.count).")
|
||||
SnodeAPI.snodeFailureCount[snode] = 0
|
||||
}
|
||||
}
|
||||
|
@ -321,8 +324,12 @@ public final class SnodeAPI : NSObject {
|
|||
return SnodeAPI.SnodeAPIError.clockOutOfSync
|
||||
case 421:
|
||||
// The snode isn't associated with the given public key anymore
|
||||
print("[Loki] Invalidating swarm for: \(publicKey).")
|
||||
SnodeAPI.dropSnodeFromSwarmIfNeeded(snode, publicKey: publicKey)
|
||||
if let publicKey = publicKey {
|
||||
print("[Loki] Invalidating swarm for: \(publicKey).")
|
||||
SnodeAPI.dropSnodeFromSwarmIfNeeded(snode, publicKey: publicKey)
|
||||
} else {
|
||||
print("[Loki] Got a 421 without an associated public key.")
|
||||
}
|
||||
case 432:
|
||||
// The proof of work difficulty is too low
|
||||
if let powDifficulty = json?["difficulty"] as? UInt {
|
||||
|
|
|
@ -13,6 +13,7 @@ import PromiseKit
|
|||
@objc(LKClosedGroupsProtocol)
|
||||
public final class ClosedGroupsProtocol : NSObject {
|
||||
public static let isSharedSenderKeysEnabled = false
|
||||
public static let groupSizeLimit = 10
|
||||
|
||||
// MARK: - Sending
|
||||
|
||||
|
@ -54,6 +55,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
// Send a closed group update message to all members (and their linked devices) using established channels
|
||||
var promises: [Promise<Void>] = []
|
||||
for member in members { // Not `membersAndLinkedDevices` as this internally takes care of multi device already
|
||||
guard member != userPublicKey else { continue }
|
||||
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
|
||||
thread.save(with: transaction)
|
||||
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name,
|
||||
|
@ -182,6 +184,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
||||
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
||||
for member in members { // This internally takes care of multi device
|
||||
guard member != userPublicKey else { continue }
|
||||
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
|
||||
thread.save(with: transaction)
|
||||
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey)
|
||||
|
@ -201,6 +204,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
}
|
||||
|
||||
public static func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
|
||||
print("[Loki] Requesting sender key for group public key: \(groupPublicKey), sender public key: \(senderPublicKey).")
|
||||
// Establish session if needed
|
||||
SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction)
|
||||
// Send the request
|
||||
|
@ -286,7 +290,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
}
|
||||
let group = thread.groupModel
|
||||
// Check that the sender is a member of the group (before the update)
|
||||
var membersAndLinkedDevices: Set<String> = Set(group.groupMemberIds)
|
||||
var membersAndLinkedDevices: Set<String> = Set(members)
|
||||
for member in group.groupMemberIds {
|
||||
let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction)
|
||||
membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.publicKey, $0.slave.publicKey ] })
|
||||
|
@ -315,6 +319,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
||||
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
||||
for member in members {
|
||||
guard member != userPublicKey else { continue }
|
||||
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
|
||||
thread.save(with: transaction)
|
||||
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.senderKey(groupPublicKey: Data(hex: groupPublicKey), senderKey: userSenderKey)
|
||||
|
@ -354,6 +359,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
return print("[Loki] Ignoring closed group sender key request from non-member.")
|
||||
}
|
||||
// Respond to the request
|
||||
print("[Loki] Responding to sender key request from: \(senderPublicKey).")
|
||||
SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) // This internally takes care of multi device
|
||||
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
||||
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
||||
|
@ -389,6 +395,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
|||
return print("[Loki] Ignoring invalid closed group sender key.")
|
||||
}
|
||||
// Store the sender key
|
||||
print("[Loki] Received a sender key from: \(senderPublicKey).")
|
||||
let ratchet = ClosedGroupRatchet(chainKey: senderKey.chainKey.toHexString(), keyIndex: UInt(senderKey.keyIndex), messageKeys: [])
|
||||
Storage.setClosedGroupRatchet(for: groupPublicKey, senderPublicKey: senderPublicKey, ratchet: ratchet, using: transaction)
|
||||
}
|
||||
|
|
|
@ -133,7 +133,17 @@ public final class SharedSenderKeysImplementation : NSObject, SharedSenderKeysPr
|
|||
}
|
||||
|
||||
public func encrypt(_ plaintext: Data, for groupPublicKey: String, senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) throws -> (ivAndCiphertext: Data, keyIndex: UInt) {
|
||||
let ratchet = try stepRatchetOnce(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction)
|
||||
let ratchet: ClosedGroupRatchet
|
||||
do {
|
||||
ratchet = try stepRatchetOnce(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction)
|
||||
} catch {
|
||||
// FIXME: It'd be cleaner to handle this in OWSMessageDecrypter (where all the other decryption errors are handled), but this was a lot more
|
||||
// convenient because there's an easy way to get the sender public key from here.
|
||||
if case RatchetingError.loadingFailed(_, _) = error {
|
||||
ClosedGroupsProtocol.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
let iv = Data.getSecureRandomData(ofSize: SharedSenderKeysImplementation.ivSize)!
|
||||
let gcm = GCM(iv: iv.bytes, tagLength: Int(SharedSenderKeysImplementation.gcmTagSize), mode: .combined)
|
||||
let messageKey = ratchet.messageKeys.last!
|
||||
|
|
|
@ -39,9 +39,14 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
|||
@property (nonatomic, readonly) uint64_t timestamp;
|
||||
@property (nonatomic, readonly) uint64_t sortId;
|
||||
@property (nonatomic, readonly) uint64_t receivedAtTimestamp;
|
||||
@property (nonatomic, readonly) BOOL shouldUseServerTime;
|
||||
/// Used for public chats where a message sent from a slave device is interpreted as having been sent from the master device.
|
||||
@property (nonatomic) NSString *actualSenderHexEncodedPublicKey;
|
||||
|
||||
- (void)setServerTimestampToReceivedTimestamp:(uint64_t)receivedAtTimestamp;
|
||||
|
||||
- (uint64_t)timestampForUI;
|
||||
|
||||
- (NSDate *)receivedAtDate;
|
||||
|
||||
- (OWSInteractionType)interactionType;
|
||||
|
|
|
@ -41,6 +41,8 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
|
||||
@implementation TSInteraction
|
||||
|
||||
@synthesize timestamp = _timestamp;
|
||||
|
||||
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
|
||||
ofClass:(Class)clazz
|
||||
withTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
|
@ -175,11 +177,25 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
|
||||
#pragma mark Date operations
|
||||
|
||||
- (uint64_t)timestampForUI
|
||||
{
|
||||
if (_shouldUseServerTime) {
|
||||
return _receivedAtTimestamp;
|
||||
}
|
||||
return _timestamp;
|
||||
}
|
||||
|
||||
- (uint64_t)timestampForLegacySorting
|
||||
{
|
||||
return self.timestamp;
|
||||
}
|
||||
|
||||
- (void)setServerTimestampToReceivedTimestamp:(uint64_t)receivedAtTimestamp
|
||||
{
|
||||
_shouldUseServerTime = YES;
|
||||
_receivedAtTimestamp = receivedAtTimestamp;
|
||||
}
|
||||
|
||||
- (NSDate *)receivedAtDate
|
||||
{
|
||||
return [NSDate ows_dateWithMillisecondsSince1970:self.receivedAtTimestamp];
|
||||
|
|
|
@ -915,6 +915,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSRecordTranscriptJob
|
||||
processIncomingSentMessageTranscript:transcript
|
||||
serverID:0
|
||||
serverTimestamp:0
|
||||
attachmentHandler:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSAssertDebug(attachmentStreams.count == 1);
|
||||
TSAttachmentStream *attachmentStream = attachmentStreams.firstObject;
|
||||
|
@ -943,6 +944,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSRecordTranscriptJob
|
||||
processIncomingSentMessageTranscript:transcript
|
||||
serverID:(serverID ?: 0)
|
||||
serverTimestamp:(uint64_t)envelope.serverTimestamp
|
||||
attachmentHandler:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
||||
OWSLogDebug(@"successfully fetched transcript attachments: %lu",
|
||||
(unsigned long)attachmentStreams.count);
|
||||
|
@ -1417,6 +1419,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
serverTimestamp:serverTimestamp
|
||||
wasReceivedByUD:wasReceivedByUD];
|
||||
|
||||
// For open group messages, use the server timestamp as the received timestamp
|
||||
if (oldGroupThread.isPublicChat) {
|
||||
[incomingMessage setServerTimestampToReceivedTimestamp:(uint64_t)envelope.serverTimestamp];
|
||||
}
|
||||
|
||||
// Loki: Set open group server ID if needed
|
||||
if (dataMessage.publicChatInfo != nil && dataMessage.publicChatInfo.hasServerID) {
|
||||
incomingMessage.openGroupServerMessageID = dataMessage.publicChatInfo.serverID;
|
||||
|
|
Loading…
Reference in a new issue