From 53a4dff9ddd18ca258d9bf20f1e9e27c5f340aed Mon Sep 17 00:00:00 2001
From: Ryan ZHAO <ryanzhaors@qq.com>
Date: Tue, 18 May 2021 16:42:08 +1000
Subject: [PATCH 01/10] fix move-insert conflict

---
 Session/Home/HomeVC.swift | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift
index 20a70778f..2808e224f 100644
--- a/Session/Home/HomeVC.swift
+++ b/Session/Home/HomeVC.swift
@@ -226,12 +226,26 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
             switch rowChange.type {
             case .delete: tableView.deleteRows(at: [ rowChange.indexPath! ], with: UITableView.RowAnimation.automatic)
             case .insert: tableView.insertRows(at: [ rowChange.newIndexPath! ], with: UITableView.RowAnimation.automatic)
-            case .move: tableView.moveRow(at: rowChange.indexPath!, to: rowChange.newIndexPath!)
             case .update: tableView.reloadRows(at: [ rowChange.indexPath! ], with: UITableView.RowAnimation.automatic)
             default: break
             }
         }
         tableView.endUpdates()
+        // HACK: Moves can have conflicts with other 3 types of change.
+        // Just batch perform all the moves seperately to prevent crashing.
+        // Since all the changes are from original state to final state,
+        // it will still be correct if we pick the Moves out.
+        tableView.beginUpdates()
+        rowChanges.forEach { rowChange in
+            let rowChange = rowChange as! YapDatabaseViewRowChange
+            let key = rowChange.collectionKey.key
+            threadViewModelCache[key] = nil
+            switch rowChange.type {
+            case .move: tableView.moveRow(at: rowChange.indexPath!, to: rowChange.newIndexPath!)
+            default: break
+            }
+        }
+        tableView.endUpdates()
         emptyStateView.isHidden = (threadCount != 0)
     }
     

From c36cf1a36d1fb1ccea7da5acc2846854854a0c8d Mon Sep 17 00:00:00 2001
From: nielsandriesse <andriesseniels@gmail.com>
Date: Wed, 19 May 2021 08:42:58 +1000
Subject: [PATCH 02/10] Hopefully fix closed group handling bug

---
 Session/Utilities/BackgroundPoller.swift       |  2 +-
 .../Sending & Receiving/MessageReceiver.swift  | 18 +++++++++++++-----
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/Session/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift
index d16570ae1..4ce1f8147 100644
--- a/Session/Utilities/BackgroundPoller.swift
+++ b/Session/Utilities/BackgroundPoller.swift
@@ -43,7 +43,7 @@ public final class BackgroundPoller : NSObject {
     }
     
     private static func getMessages(for publicKey: String) -> Promise<Void> {
-        return SnodeAPI.getSwarm(for: publicKey).then2 { swarm -> Promise<Void> in
+        return SnodeAPI.getSwarm(for: publicKey).then(on: DispatchQueue.main) { swarm -> Promise<Void> in
             guard let snode = swarm.randomElement() else { throw SnodeAPI.Error.generic }
             return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise<Void> in
                 let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey)
diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift
index cf724fe9f..8e6e53bca 100644
--- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift	
+++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift	
@@ -54,11 +54,6 @@ public enum MessageReceiver {
         // Parse the envelope
         let envelope = try SNProtoEnvelope.parseData(data)
         let storage = SNMessagingKitConfiguration.shared.storage
-        // If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp
-        // will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround
-        // for this issue.
-        guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) || isRetry else { throw Error.duplicateMessage }
-        storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction)
         // Decrypt the contents
         guard let ciphertext = envelope.content else { throw Error.noData }
         var plaintext: Data!
@@ -159,6 +154,19 @@ public enum MessageReceiver {
             guard isValid else {
                 throw Error.invalidMessage
             }
+            // If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp
+            // will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround
+            // for this issue.
+            if let message = message as? ClosedGroupControlMessage, case .new = message.kind {
+                // Allow duplicates in this case to avoid the following situation:
+                // • The app performed a background poll or received a push notification
+                // • This method was invoked and the received message timestamps table was updated
+                // • Processing wasn't finished
+                // • The user doesn't see the new closed group
+            } else {
+                guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) || isRetry else { throw Error.duplicateMessage }
+                storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction)
+            }
             // Return
             return (message, proto)
         } else {

From 6760341a2e7a56348828c2d1808088d75ca42b40 Mon Sep 17 00:00:00 2001
From: nielsandriesse <andriesseniels@gmail.com>
Date: Wed, 19 May 2021 08:49:20 +1000
Subject: [PATCH 03/10] Add missing retry

---
 Session/Utilities/BackgroundPoller.swift | 31 +++++++++++-------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/Session/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift
index 4ce1f8147..3a79a7450 100644
--- a/Session/Utilities/BackgroundPoller.swift
+++ b/Session/Utilities/BackgroundPoller.swift
@@ -13,12 +13,6 @@ public final class BackgroundPoller : NSObject {
         promises = []
         promises.append(pollForMessages())
         promises.append(contentsOf: pollForClosedGroupMessages())
-        let openGroups: [String:OpenGroup] = Storage.shared.getAllUserOpenGroups()
-        openGroups.values.forEach { openGroup in
-            let poller = OpenGroupPoller(for: openGroup)
-            poller.stop()
-            promises.append(poller.pollForNewMessages(isBackgroundPoll: true))
-        }
         let v2OpenGroupServers = Set(Storage.shared.getAllV2OpenGroups().values.map { $0.server })
         v2OpenGroupServers.forEach { server in
             let poller = OpenGroupPollerV2(for: server)
@@ -27,7 +21,8 @@ public final class BackgroundPoller : NSObject {
         }
         when(resolved: promises).done { _ in
             completionHandler(.newData)
-        }.catch { _ in
+        }.catch { error in
+            SNLog("Background poll failed due to error: \(error)")
             completionHandler(.failed)
         }
     }
@@ -45,17 +40,19 @@ public final class BackgroundPoller : NSObject {
     private static func getMessages(for publicKey: String) -> Promise<Void> {
         return SnodeAPI.getSwarm(for: publicKey).then(on: DispatchQueue.main) { swarm -> Promise<Void> in
             guard let snode = swarm.randomElement() else { throw SnodeAPI.Error.generic }
-            return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise<Void> in
-                let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey)
-                let promises = messages.compactMap { json -> Promise<Void>? in
-                    // Use a best attempt approach here; we don't want to fail the entire process if one of the
-                    // messages failed to parse.
-                    guard let envelope = SNProtoEnvelope.from(json),
-                        let data = try? envelope.serializedData() else { return nil }
-                    let job = MessageReceiveJob(data: data, isBackgroundPoll: true)
-                    return job.execute()
+            return attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.main) {
+                return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise<Void> in
+                    let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey)
+                    let promises = messages.compactMap { json -> Promise<Void>? in
+                        // Use a best attempt approach here; we don't want to fail the entire process if one of the
+                        // messages failed to parse.
+                        guard let envelope = SNProtoEnvelope.from(json),
+                            let data = try? envelope.serializedData() else { return nil }
+                        let job = MessageReceiveJob(data: data, isBackgroundPoll: true)
+                        return job.execute()
+                    }
+                    return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects
                 }
-                return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects
             }
         }
     }

From 8338ba3eca7fafca99715eeafd799ed6cc835e45 Mon Sep 17 00:00:00 2001
From: nielsandriesse <andriesseniels@gmail.com>
Date: Wed, 19 May 2021 13:32:42 +1000
Subject: [PATCH 04/10] Update build number

---
 Session.xcodeproj/project.pbxproj | 12 ++++++------
 Session/Home/HomeVC.swift         |  8 ++++----
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj
index 0a21b22a2..52eced0e1 100644
--- a/Session.xcodeproj/project.pbxproj
+++ b/Session.xcodeproj/project.pbxproj
@@ -5138,7 +5138,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 246;
+				CURRENT_PROJECT_VERSION = 247;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@@ -5207,7 +5207,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 246;
+				CURRENT_PROJECT_VERSION = 247;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				ENABLE_NS_ASSERTIONS = NO;
@@ -5268,7 +5268,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 246;
+				CURRENT_PROJECT_VERSION = 247;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@@ -5338,7 +5338,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 246;
+				CURRENT_PROJECT_VERSION = 247;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				ENABLE_NS_ASSERTIONS = NO;
@@ -6223,7 +6223,7 @@
 				CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 246;
+				CURRENT_PROJECT_VERSION = 247;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
@@ -6291,7 +6291,7 @@
 				CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 246;
+				CURRENT_PROJECT_VERSION = 247;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift
index 2808e224f..9fde3b929 100644
--- a/Session/Home/HomeVC.swift
+++ b/Session/Home/HomeVC.swift
@@ -231,10 +231,10 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
             }
         }
         tableView.endUpdates()
-        // HACK: Moves can have conflicts with other 3 types of change.
-        // Just batch perform all the moves seperately to prevent crashing.
-        // Since all the changes are from original state to final state,
-        // it will still be correct if we pick the Moves out.
+        // HACK: Moves can have conflicts with the other 3 types of change.
+        // Just batch perform all the moves separately to prevent crashing.
+        // Since all the changes are from the original state to the final state,
+        // it will still be correct if we pick the moves out.
         tableView.beginUpdates()
         rowChanges.forEach { rowChange in
             let rowChange = rowChange as! YapDatabaseViewRowChange

From 8dffa249bbd89a26b295906869088ed25073cd09 Mon Sep 17 00:00:00 2001
From: nielsandriesse <andriesseniels@gmail.com>
Date: Wed, 19 May 2021 13:43:24 +1000
Subject: [PATCH 05/10] Update version number

---
 Session.xcodeproj/project.pbxproj | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj
index 52eced0e1..25ade3331 100644
--- a/Session.xcodeproj/project.pbxproj
+++ b/Session.xcodeproj/project.pbxproj
@@ -5159,7 +5159,7 @@
 				INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.0;
+				MARKETING_VERSION = 1.11.1;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -5233,7 +5233,7 @@
 				INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.0;
+				MARKETING_VERSION = 1.11.1;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -5287,7 +5287,7 @@
 				INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.0;
+				MARKETING_VERSION = 1.11.1;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@@ -5362,7 +5362,7 @@
 				INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.0;
+				MARKETING_VERSION = 1.11.1;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@@ -6259,7 +6259,7 @@
 					"$(SRCROOT)",
 				);
 				LLVM_LTO = NO;
-				MARKETING_VERSION = 1.11.0;
+				MARKETING_VERSION = 1.11.1;
 				OTHER_LDFLAGS = "$(inherited)";
 				OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
@@ -6327,7 +6327,7 @@
 					"$(SRCROOT)",
 				);
 				LLVM_LTO = NO;
-				MARKETING_VERSION = 1.11.0;
+				MARKETING_VERSION = 1.11.1;
 				OTHER_LDFLAGS = "$(inherited)";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
 				PRODUCT_NAME = Session;

From 4da8a0933c5db5b7d1cbe7192e8ccdd977624c2e Mon Sep 17 00:00:00 2001
From: nielsandriesse <andriesseniels@gmail.com>
Date: Wed, 19 May 2021 15:15:54 +1000
Subject: [PATCH 06/10] Add file server instability modal

---
 Session.xcodeproj/project.pbxproj             |  4 ++
 Session/Home/HomeVC.swift                     |  8 ++++
 Session/Sheets & Modals/FileServerModal.swift | 44 +++++++++++++++++++
 .../General/SNUserDefaults.swift              |  1 +
 4 files changed, 57 insertions(+)
 create mode 100644 Session/Sheets & Modals/FileServerModal.swift

diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj
index 25ade3331..322724eb6 100644
--- a/Session.xcodeproj/project.pbxproj
+++ b/Session.xcodeproj/project.pbxproj
@@ -773,6 +773,7 @@
 		C3DB66CC260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */; };
 		C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; };
 		C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; };
+		C3ECBBDB2654D4640081996B /* FileServerModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBBDA2654D4640081996B /* FileServerModal.swift */; };
 		C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; };
 		C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; };
 		D2179CFC16BB0B3A0006F3AB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */; };
@@ -1762,6 +1763,7 @@
 		C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = "<group>"; };
 		C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = "<group>"; };
 		C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = "<group>"; };
+		C3ECBBDA2654D4640081996B /* FileServerModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileServerModal.swift; sourceTree = "<group>"; };
 		C3ECBF7A257056B700EA7FCE /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
 		C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
 		C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -2872,6 +2874,7 @@
 				B8A14D6F2589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift */,
 				B86BD08323399ACF000F5AE3 /* Modal.swift */,
 				C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */,
+				C3ECBBDA2654D4640081996B /* FileServerModal.swift */,
 			);
 			path = "Sheets & Modals";
 			sourceTree = "<group>";
@@ -4888,6 +4891,7 @@
 				34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */,
 				450DF2051E0D74AC003D14BE /* Platform.swift in Sources */,
 				4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */,
+				C3ECBBDB2654D4640081996B /* FileServerModal.swift in Sources */,
 				B82149B825D60393009C0F2A /* BlockedModal.swift in Sources */,
 				B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */,
 				346129991FD1E4DA00532771 /* SignalApp.m in Sources */,
diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift
index 9fde3b929..688aed4b7 100644
--- a/Session/Home/HomeVC.swift
+++ b/Session/Home/HomeVC.swift
@@ -164,6 +164,14 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
     override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
         reload()
+        let userDefaults = UserDefaults.standard
+        if !userDefaults[.hasSeenFileServerInstabilityNotification] {
+            let fileServerModal = FileServerModal()
+            fileServerModal.modalPresentationStyle = .overFullScreen
+            fileServerModal.modalTransitionStyle = .crossDissolve
+            present(fileServerModal, animated: true, completion: nil)
+            userDefaults[.hasSeenFileServerInstabilityNotification] = true
+        }
     }
     
     deinit {
diff --git a/Session/Sheets & Modals/FileServerModal.swift b/Session/Sheets & Modals/FileServerModal.swift
new file mode 100644
index 000000000..d4a036fb3
--- /dev/null
+++ b/Session/Sheets & Modals/FileServerModal.swift	
@@ -0,0 +1,44 @@
+
+final class FileServerModal : Modal {
+
+    override func populateContentView() {
+        // Title
+        let titleLabel = UILabel()
+        titleLabel.textColor = Colors.text
+        titleLabel.font = .boldSystemFont(ofSize: Values.largeFontSize)
+        titleLabel.text = "Session"
+        titleLabel.textAlignment = .center
+        // Message
+        let messageLabel = UILabel()
+        messageLabel.textColor = Colors.text
+        messageLabel.font = .systemFont(ofSize: Values.smallFontSize)
+        let message = "We're upgrading the way files are stored. File transfer may be unstable for the next 24-48 hours."
+        messageLabel.text = message
+        messageLabel.numberOfLines = 0
+        messageLabel.lineBreakMode = .byWordWrapping
+        messageLabel.textAlignment = .center
+        // OK button
+        let okButton = UIButton()
+        okButton.set(.height, to: Values.mediumButtonHeight)
+        okButton.layer.cornerRadius = Modal.buttonCornerRadius
+        okButton.backgroundColor = Colors.buttonBackground
+        okButton.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize)
+        okButton.setTitleColor(Colors.text, for: UIControl.State.normal)
+        okButton.setTitle("OK", for: UIControl.State.normal)
+        okButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside)
+        // Button stack view
+        let buttonStackView = UIStackView(arrangedSubviews: [ okButton ])
+        buttonStackView.axis = .horizontal
+        buttonStackView.spacing = Values.mediumSpacing
+        buttonStackView.distribution = .fillEqually
+        // Main stack view
+        let mainStackView = UIStackView(arrangedSubviews: [ titleLabel, messageLabel, buttonStackView ])
+        mainStackView.axis = .vertical
+        mainStackView.spacing = Values.largeSpacing
+        contentView.addSubview(mainStackView)
+        mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing)
+        mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing)
+        contentView.pin(.trailing, to: .trailing, of: mainStackView, withInset: Values.largeSpacing)
+        contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.largeSpacing)
+    }
+}
diff --git a/SessionUtilitiesKit/General/SNUserDefaults.swift b/SessionUtilitiesKit/General/SNUserDefaults.swift
index aa563e94f..982fabe4f 100644
--- a/SessionUtilitiesKit/General/SNUserDefaults.swift
+++ b/SessionUtilitiesKit/General/SNUserDefaults.swift
@@ -8,6 +8,7 @@ public enum SNUserDefaults {
         case hasSeenLinkPreviewSuggestion
         case isUsingFullAPNs
         case isMigratingToV2KeyPair
+        case hasSeenFileServerInstabilityNotification
     }
 
     public enum Date : Swift.String {

From 20e0103d2df3271e8c9368616054bf11f898bffd Mon Sep 17 00:00:00 2001
From: Niels Andriesse <andriesseniels@gmail.com>
Date: Thu, 20 May 2021 10:53:56 +1000
Subject: [PATCH 07/10] Switch to dedicated server

---
 .../File Server/FileServerAPIV2.swift         | 22 +++++++++++--------
 .../Jobs/AttachmentDownloadJob.swift          |  5 +++--
 SignalUtilitiesKit/To Do/OWSProfileManager.m  |  5 +++--
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/SessionMessagingKit/File Server/FileServerAPIV2.swift b/SessionMessagingKit/File Server/FileServerAPIV2.swift
index dd19b528c..16146b59a 100644
--- a/SessionMessagingKit/File Server/FileServerAPIV2.swift	
+++ b/SessionMessagingKit/File Server/FileServerAPIV2.swift	
@@ -5,8 +5,10 @@ import SessionSnodeKit
 public final class FileServerAPIV2 : NSObject {
     
     // MARK: Settings
-    @objc public static let server = "http://88.99.175.227"
-    public static let serverPublicKey = "7cb31905b55cd5580c686911debf672577b3fb0bff81df4ce2d5c4cb3a7aaa69"
+    @objc public static let oldServer = "http://88.99.175.227"
+    public static let oldServerPublicKey = "7cb31905b55cd5580c686911debf672577b3fb0bff81df4ce2d5c4cb3a7aaa69"
+    @objc public static let server = "http://filev2.getsession.org"
+    public static let serverPublicKey = "da21e1d886c6fbaea313f75298bd64aab03a97ce985b46bb2dad9f2089c8ee59"
     
     // MARK: Initialization
     private override init() { }
@@ -47,7 +49,9 @@ public final class FileServerAPIV2 : NSObject {
     }
     
     // MARK: Convenience
-    private static func send(_ request: Request) -> Promise<JSON> {
+    private static func send(_ request: Request, useOldServer: Bool) -> Promise<JSON> {
+        let server = useOldServer ? oldServer : server
+        let serverPublicKey = useOldServer ? oldServerPublicKey : serverPublicKey
         let tsRequest: TSRequest
         switch request.verb {
         case .get:
@@ -81,21 +85,21 @@ public final class FileServerAPIV2 : NSObject {
         let base64EncodedFile = file.base64EncodedString()
         let parameters = [ "file" : base64EncodedFile ]
         let request = Request(verb: .post, endpoint: "files", parameters: parameters)
-        return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
+        return send(request, useOldServer: false).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
             guard let fileID = json["result"] as? UInt64 else { throw Error.parsingFailed }
             return fileID
         }
     }
     
-    @objc(download:)
-    public static func objc_download(file: String) -> AnyPromise {
+    @objc(download:useOldServer:)
+    public static func objc_download(file: String, useOldServer: Bool) -> AnyPromise {
         guard let id = UInt64(file) else { return AnyPromise.from(Promise<Data>(error: Error.invalidURL)) }
-        return AnyPromise.from(download(id))
+        return AnyPromise.from(download(id, useOldServer: useOldServer))
     }
     
-    public static func download(_ file: UInt64) -> Promise<Data> {
+    public static func download(_ file: UInt64, useOldServer: Bool) -> Promise<Data> {
         let request = Request(verb: .get, endpoint: "files/\(file)")
-        return send(request).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
+        return send(request, useOldServer: useOldServer).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
             guard let base64EncodedFile = json["result"] as? String, let file = Data(base64Encoded: base64EncodedFile) else { throw Error.parsingFailed }
             return file
         }
diff --git a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift
index d9b96b5b9..ef1897af7 100644
--- a/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift
+++ b/SessionMessagingKit/Jobs/AttachmentDownloadJob.swift
@@ -100,11 +100,12 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject
             }.catch(on: DispatchQueue.global()) { error in
                 handleFailure(error)
             }
-        } else if pointer.downloadURL.contains(FileServerAPIV2.server) {
+        } else if pointer.downloadURL.contains(FileServerAPIV2.server) || pointer.downloadURL.contains(FileServerAPIV2.oldServer) {
             guard let fileAsString = pointer.downloadURL.split(separator: "/").last, let file = UInt64(fileAsString) else {
                 return handleFailure(Error.invalidURL)
             }
-            FileServerAPIV2.download(file).done(on: DispatchQueue.global(qos: .userInitiated)) { data in
+            let useOldServer = pointer.downloadURL.contains(FileServerAPIV2.oldServer)
+            FileServerAPIV2.download(file, useOldServer: useOldServer).done(on: DispatchQueue.global(qos: .userInitiated)) { data in
                 self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure)
             }.catch(on: DispatchQueue.global()) { error in
                 handleFailure(error)
diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m
index c37b850f9..afc9428cc 100644
--- a/SignalUtilitiesKit/To Do/OWSProfileManager.m	
+++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m	
@@ -806,9 +806,10 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
         NSString *profilePictureURL = userProfile.avatarUrlPath;
         
         AnyPromise *promise;
-        if ([profilePictureURL containsString:SNFileServerAPIV2.server]) {
+        if ([profilePictureURL containsString:SNFileServerAPIV2.server] || [profilePictureURL containsString:SNFileServerAPIV2.oldServer]) {
             NSString *file = [profilePictureURL lastPathComponent];
-            promise = [SNFileServerAPIV2 download:file];
+            BOOL useOldServer = [profilePictureURL containsString:SNFileServerAPIV2.oldServer];
+            promise = [SNFileServerAPIV2 download:file useOldServer:useOldServer];
         } else {
             promise = [SNFileServerAPI downloadAttachmentFrom:profilePictureURL];
         }

From 08fc17e0f9c1203528fd89191d5d6be6cd7a9a7e Mon Sep 17 00:00:00 2001
From: Niels Andriesse <andriesseniels@gmail.com>
Date: Thu, 20 May 2021 12:03:59 +1000
Subject: [PATCH 08/10] Remove file server instability modal

---
 Session.xcodeproj/project.pbxproj             |  4 --
 Session/Home/HomeVC.swift                     |  8 ----
 Session/Sheets & Modals/FileServerModal.swift | 44 -------------------
 .../General/SNUserDefaults.swift              |  1 -
 4 files changed, 57 deletions(-)
 delete mode 100644 Session/Sheets & Modals/FileServerModal.swift

diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj
index 322724eb6..25ade3331 100644
--- a/Session.xcodeproj/project.pbxproj
+++ b/Session.xcodeproj/project.pbxproj
@@ -773,7 +773,6 @@
 		C3DB66CC260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */; };
 		C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; };
 		C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; };
-		C3ECBBDB2654D4640081996B /* FileServerModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBBDA2654D4640081996B /* FileServerModal.swift */; };
 		C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; };
 		C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; };
 		D2179CFC16BB0B3A0006F3AB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */; };
@@ -1763,7 +1762,6 @@
 		C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = "<group>"; };
 		C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = "<group>"; };
 		C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = "<group>"; };
-		C3ECBBDA2654D4640081996B /* FileServerModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileServerModal.swift; sourceTree = "<group>"; };
 		C3ECBF7A257056B700EA7FCE /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
 		C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
 		C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -2874,7 +2872,6 @@
 				B8A14D6F2589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift */,
 				B86BD08323399ACF000F5AE3 /* Modal.swift */,
 				C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */,
-				C3ECBBDA2654D4640081996B /* FileServerModal.swift */,
 			);
 			path = "Sheets & Modals";
 			sourceTree = "<group>";
@@ -4891,7 +4888,6 @@
 				34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */,
 				450DF2051E0D74AC003D14BE /* Platform.swift in Sources */,
 				4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */,
-				C3ECBBDB2654D4640081996B /* FileServerModal.swift in Sources */,
 				B82149B825D60393009C0F2A /* BlockedModal.swift in Sources */,
 				B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */,
 				346129991FD1E4DA00532771 /* SignalApp.m in Sources */,
diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift
index 688aed4b7..9fde3b929 100644
--- a/Session/Home/HomeVC.swift
+++ b/Session/Home/HomeVC.swift
@@ -164,14 +164,6 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
     override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
         reload()
-        let userDefaults = UserDefaults.standard
-        if !userDefaults[.hasSeenFileServerInstabilityNotification] {
-            let fileServerModal = FileServerModal()
-            fileServerModal.modalPresentationStyle = .overFullScreen
-            fileServerModal.modalTransitionStyle = .crossDissolve
-            present(fileServerModal, animated: true, completion: nil)
-            userDefaults[.hasSeenFileServerInstabilityNotification] = true
-        }
     }
     
     deinit {
diff --git a/Session/Sheets & Modals/FileServerModal.swift b/Session/Sheets & Modals/FileServerModal.swift
deleted file mode 100644
index d4a036fb3..000000000
--- a/Session/Sheets & Modals/FileServerModal.swift	
+++ /dev/null
@@ -1,44 +0,0 @@
-
-final class FileServerModal : Modal {
-
-    override func populateContentView() {
-        // Title
-        let titleLabel = UILabel()
-        titleLabel.textColor = Colors.text
-        titleLabel.font = .boldSystemFont(ofSize: Values.largeFontSize)
-        titleLabel.text = "Session"
-        titleLabel.textAlignment = .center
-        // Message
-        let messageLabel = UILabel()
-        messageLabel.textColor = Colors.text
-        messageLabel.font = .systemFont(ofSize: Values.smallFontSize)
-        let message = "We're upgrading the way files are stored. File transfer may be unstable for the next 24-48 hours."
-        messageLabel.text = message
-        messageLabel.numberOfLines = 0
-        messageLabel.lineBreakMode = .byWordWrapping
-        messageLabel.textAlignment = .center
-        // OK button
-        let okButton = UIButton()
-        okButton.set(.height, to: Values.mediumButtonHeight)
-        okButton.layer.cornerRadius = Modal.buttonCornerRadius
-        okButton.backgroundColor = Colors.buttonBackground
-        okButton.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize)
-        okButton.setTitleColor(Colors.text, for: UIControl.State.normal)
-        okButton.setTitle("OK", for: UIControl.State.normal)
-        okButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside)
-        // Button stack view
-        let buttonStackView = UIStackView(arrangedSubviews: [ okButton ])
-        buttonStackView.axis = .horizontal
-        buttonStackView.spacing = Values.mediumSpacing
-        buttonStackView.distribution = .fillEqually
-        // Main stack view
-        let mainStackView = UIStackView(arrangedSubviews: [ titleLabel, messageLabel, buttonStackView ])
-        mainStackView.axis = .vertical
-        mainStackView.spacing = Values.largeSpacing
-        contentView.addSubview(mainStackView)
-        mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing)
-        mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing)
-        contentView.pin(.trailing, to: .trailing, of: mainStackView, withInset: Values.largeSpacing)
-        contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.largeSpacing)
-    }
-}
diff --git a/SessionUtilitiesKit/General/SNUserDefaults.swift b/SessionUtilitiesKit/General/SNUserDefaults.swift
index 982fabe4f..aa563e94f 100644
--- a/SessionUtilitiesKit/General/SNUserDefaults.swift
+++ b/SessionUtilitiesKit/General/SNUserDefaults.swift
@@ -8,7 +8,6 @@ public enum SNUserDefaults {
         case hasSeenLinkPreviewSuggestion
         case isUsingFullAPNs
         case isMigratingToV2KeyPair
-        case hasSeenFileServerInstabilityNotification
     }
 
     public enum Date : Swift.String {

From c84a94247892a416c42bfe708118565bf057f4d1 Mon Sep 17 00:00:00 2001
From: Niels Andriesse <andriesseniels@gmail.com>
Date: Thu, 20 May 2021 13:57:42 +1000
Subject: [PATCH 09/10] Fix push notification handling

This was crashing every time the extension started
---
 SessionMessagingKit/Database/OWSPrimaryStorage.m | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/SessionMessagingKit/Database/OWSPrimaryStorage.m b/SessionMessagingKit/Database/OWSPrimaryStorage.m
index d35635cae..ae897bf48 100644
--- a/SessionMessagingKit/Database/OWSPrimaryStorage.m
+++ b/SessionMessagingKit/Database/OWSPrimaryStorage.m
@@ -69,9 +69,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
         _dbReadPool = [[YapDatabaseConnectionPool alloc] initWithDatabase:self.database];
         _dbReadWriteConnection = [self newDatabaseConnection];
         _uiDatabaseConnection = [self newDatabaseConnection];
-
-        // Vacuum the database
-        [self.dbReadWriteConnection vacuum];
         
         // Increase object cache limit. Default is 250.
         _uiDatabaseConnection.objectCacheLimit = 500;

From fe3493ff127431a2e77418c7571754e4d0aa58f4 Mon Sep 17 00:00:00 2001
From: Niels Andriesse <andriesseniels@gmail.com>
Date: Thu, 20 May 2021 13:58:31 +1000
Subject: [PATCH 10/10] Update version number

---
 Session.xcodeproj/project.pbxproj | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj
index 25ade3331..878709073 100644
--- a/Session.xcodeproj/project.pbxproj
+++ b/Session.xcodeproj/project.pbxproj
@@ -5138,7 +5138,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 247;
+				CURRENT_PROJECT_VERSION = 249;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@@ -5159,7 +5159,7 @@
 				INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.1;
+				MARKETING_VERSION = 1.11.2;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -5207,7 +5207,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 247;
+				CURRENT_PROJECT_VERSION = 249;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				ENABLE_NS_ASSERTIONS = NO;
@@ -5233,7 +5233,7 @@
 				INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.1;
+				MARKETING_VERSION = 1.11.2;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -5268,7 +5268,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 247;
+				CURRENT_PROJECT_VERSION = 249;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@@ -5287,7 +5287,7 @@
 				INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.1;
+				MARKETING_VERSION = 1.11.2;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@@ -5338,7 +5338,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 247;
+				CURRENT_PROJECT_VERSION = 249;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				ENABLE_NS_ASSERTIONS = NO;
@@ -5362,7 +5362,7 @@
 				INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 1.11.1;
+				MARKETING_VERSION = 1.11.2;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@@ -6223,7 +6223,7 @@
 				CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 247;
+				CURRENT_PROJECT_VERSION = 249;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
@@ -6259,7 +6259,7 @@
 					"$(SRCROOT)",
 				);
 				LLVM_LTO = NO;
-				MARKETING_VERSION = 1.11.1;
+				MARKETING_VERSION = 1.11.2;
 				OTHER_LDFLAGS = "$(inherited)";
 				OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
@@ -6291,7 +6291,7 @@
 				CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 247;
+				CURRENT_PROJECT_VERSION = 249;
 				DEVELOPMENT_TEAM = SUQ8J2PCT7;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
@@ -6327,7 +6327,7 @@
 					"$(SRCROOT)",
 				);
 				LLVM_LTO = NO;
-				MARKETING_VERSION = 1.11.1;
+				MARKETING_VERSION = 1.11.2;
 				OTHER_LDFLAGS = "$(inherited)";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
 				PRODUCT_NAME = Session;